Document

How to co-exist SD/MMC and I2C module
SCK/SCL
SDI/SDA
SDO
SD/MMC
CE
MCU
I2C
Device
Typ 65mA
GPS
Module
Soft
UART
SPI
SD
PIC
18F2550
Soft
I2C
2X AA Cell
Boost
DC/DC
VCC(3.3V)
LCD
Tips to handle SD card
Initialize at PWON
Cs=clk=di  high
Entering SPI mode
Raw I/O
DO
B6
B7
B7
DI
B6
CLK
GetResponse
Ret0xff
Do retry{
send 0xff
if(!(res&0xfe) break;
}
Return ret;
/CShigh
Send dummy 80 clocks (Send 0xff x 10)
/CSLow
Send 0x40,0x00,0x00,0x00,0x00,0x95
Ret=GetResponse();
While(ret==0x0){
cshigh
send 0xff
cslow
send 0x40,0x00,0x00,0x00,0x00,0x00,0x95
ret=GetResponse();
}
/cshigh
Send 0xff
Status =
Tips to handle SD card address’d read /write
DI
A3
0x40|17
Command 17
A2
A1
A0
Least command list
6Bytes command
Start
Command
Argument
CRC
Stop
“01”
6bit
32bit
7bit
“1”
CRC Required at CMD0 before changing SPI mode.
Ignored at SPI mode.
Response R1 (1Byte)
Fixed
Invalid argument
Invalid address
Erase err
CRC Err
Invalid CMD
?
Idling
“0”
1/0
1/0
1/0
1/0
1/0
1/0
1/0
Command
Arg
Response
Operation / affects
CMD0
none
R1
Reset card
CMD1
None
R1
Ask if card reset has done?
CMD16
Length
R1
Change block length used in CMD 17 and
CMD24.Default is 512.Up to 2024 bytes.Some
restrictions depend on the card.
Does not apply on write operation.
CMD17
Address
R1
Single block read.
CMD24
Address
R1
Single block write
Single block read sequence
/CS
TX
CMD16
A3 A2 A1 A0 FF
RX
R1
D0 D1 ~ D511
CRC1 CRC2
Single block write sequence
/CS
TX
CMD24
D0 D1 ~ D511
A3 A2 A1 A0 FF
R1
CRC1 CRC2
Single block read sequence
Regular task
1s Timer invocation.
Read SW.
Read and
Parse GPS Msg.
Read Batt. Volt.
Write data to SD.
Exec command
Update LCD.
FAT16
Filesystem
Software I2C
Driver
Software UART
Driver
Software I2C
Interrupt
Timer
Value
Consider benefits between
Direct execution and ISR interruption.
NOP
SCL
SDA
NOP
blank
START
state
ST
b7
b6
ACK
SM
PAYLOAD
ACK
MAX clk freq : 400kHz … 2.5us
Exec step @ 8MHz … 0.5us
@40MHz ... 0.1us
Interrupt latency … several clks
data
clk
Timer assignment
TMR0
Software serial
TMR1
Software I2C
TMR2
TMR3
Software serial (receive only)
top level interface
Underlying i/o func in ISR
char ser_getchar(void)
if RXING {
process RX until done;
} else if HAS_TX
process TX until done;
} else {
wait for RX;
}
RX buff
State diagram
INIT
TXSTBY
waiting for start bit
TMR0L  0xff //TMR0 full count
T0IF0 // Clear TMR0 flag
T0IE1 // Set TMR0 INT
RXWAITING
ser_getchar()
TXBUSY
RXBUSY
Tx not implimented
RXREADY
RXERR
b
1.5b
LSB
FIRST
ST
RXWAITING
RXBUSY
0
1
2
3
4
5
6
7
SP
RXREADY
Software serial timing consideration
interrupt
read bit
prepare for next
Counter value for
Start BIT: 1.5bit = 1.563E-4s ... 195.38
256 – 195 = 61
Other BIT: 1bit = 1.042E-4s ... 124.8
256 – 125 = 131
1/9600 = 1.042E-4s
ST
1.5bit
8MHz
40MHz
1/4
2MHz
10MHz
Prescaler
1/8
1/2
1us
1MHz
1.25MHz
0.8us
8bit Timer
(1/256)
1/104
1/130
104.17us
SPI raw level I/O
MBR
0
boot
446
P.tbl1
P.tbl2
P.tbl3
P.tbl4
signature
struct {
Byte bootDescriptor;
/* 0x80: bootable device, 0x00: non-bootable */
Byte firstPartitionSector[3]; /* 1st sector number */
Byte fileSystemDescriptor; /* 1:FAT12, 4:FAT16(less than 32MB), 5:拡張
DOS パーティション,
6:FAT16(more 32MB), 0xb:FAT32(more 2GB),
0xc:FAT32 Int32h 拡張, 0xe:FAT16 Int32h 拡張,
0xf:拡張 DOS パーティションの Int32h 拡張 */
Byte lastPartitionSector[3];
Byte firstSectorNumbers[4];
/* first sector number (link to BPB sector) */
Byte numberOfSectors[4];
} partitionTable;
firstSectorNumbers(454~457) holds
offset to logical sector 0 in little endian
ex 3E 00 00 00
3E * 512 = 7C00
PBR
7C00
JMP INST(3)
OEM NAME (8)
BIOS Param Blk(25)
Ext BIOS Param Blk(26)
Boot (448)
signature(2)
struct {
Byte bytesPerSector[2];
/* bytes/sector */
Byte sectorsPerCluster;
/* sectors/cluster */
Byte reservedSectors[2]; /* reserved sector, beginning with sector 0 */
Byte numberOfFATs;
/* file allocation table */
Byte rootEntries[2];
/* root entry (512) */
Byte totalSectors[2];
/* partion total secter */
Byte mediaDescriptor;
/* 0xf8: Hard Disk */
Byte sectorsPerFAT[2];
/* sector/FAT (FAT32 always zero: see
bigSectorsPerFAT) */
Byte sectorsPerTrack[2]; /* sector/track (not use) */
Byte heads[2];
/* heads number (not use) */
Byte hiddenSectors[4];
/* hidden sector number */
Byte bigTotalSectors[4]; /* total sector number */
} FAT16BPB;
PBR + ReservedSectors x 512
ex 7C00h + 6x512 = 8800h
8800
FAT1
27200
45C00
FAT2
Root directory entry
49C00
User Data Area
SectorsPerFat
ex F5h x 512=1EA00h
8800h+1EA00h = 27200h
ex 27200h+1EA00h = 45C00h
sizeof(Direntey) x rootEntries
ex 32 x 512 = 16384
45C00h + 16384(dec) =
typedef struct DirEntry_t {
Byte name[8];
/* file name */
Byte extension[3];
/* file name extension */
Byte attribute;
/* file attribute
bit 4 directory flag
bit 3 volume flag
bit 2 hidden flag
bit 1 system flag
bit 0 read only flag */
Byte reserved;
/* use NT or same OS */
Byte createTimeMs;
/* VFAT で使用するファイル作成時刻の10ミリ秒 (0
~ 199) */
Byte createTime[2];
/* VFAT で使用するファイル作成時間 */
Byte createDate[2];
/* VFAT で使用するファイル作成日付 */
Byte accessDate[2];
/* VFAT で使用するファイル・アクセス日付 */
Byte clusterHighWord[2]; /* FAT32 で使用するクラスタ番号の上位 16 bits */
Byte updateTime[2];
Byte updateDate[2];
Byte cluster[2];
/* start cluster number */
Byte fileSize[4];
/* file size in bytes (directory is always zero) */
};
Filesystem initialization
Read MBR
•Retrieve firstSectorNumbers
•Determine head of PBR1  firstSectorNumbers x 512
•Note We does not handle other than No.1 Partition.
Read PBR1
•Retrieve ReservedSectors, SectorsPerFAT, SectorsPerCluster, rootEntries, bigTotalSectors
•Determine head address of FAT1  PBR1 + ReservedSectors x 512
FAT2  FAT1 + SectorsPerFAT x 512
RDE  FAT2 + SectorsPerFAT x 512
UDA  RDE + 32 x rootEntries
NumSectorsOfUDA  bigTotalSectors – ReservedSectors – (UDA – FAT1)/512
UDAClusters  NumSecdtorsOfUDA / SectorsPerCluster
•Holds following information
FAT1
FAT2
SectorsPerFAT
RDE
rootEntries
UDA
UDAClusters
SectorsPerCluster
Create and write a file on filesystem
Create()
FAT1
FAT2
UDA
R
Look for unused RDE
Look for unused cluster
RDE
R
W
W
Mark 0xFF to found cluster
W
Update corresponding RDE
Write()
W
Write Data to allocated cluster
W
Update length of RDE
Update linked list of FAT
(if data occupies
beyond current cluster)
close()
Flush unwritten data
Update length of RDE
Mark 0xFF to last used cluster
W
W
Interface layer
ser_init()
ser_isr()
gps_init()
buff
ser_getchr()
buff
GPS status register
gps_parse()
coord
i2c_init()
i2c_write()
LCD
Display
time
info
V.Batt
SW
adc_read()
V.BATT
fopen()
fclose()
fwrite()
fprintf()
FAT
mm_init()
mm_read_block() spi_init()
mm_write_block() spi_trx()
MM
SPI
SD
Card
write(data, length)
buff_len
buffer[512]
sector
uda
cluster
•current_cluster
•index of sector in the curr. cluster
address 
uda + (curr.cluster -2) *
sector_per_cluster * 512
+ index_of_sector * 512
•buff_len
GPS Data format of GGA
NNorth
Altitude
SSouth
where:
dd deg
mm.mmmm
 min(resolution 1E-4)
Time in UTC
where:
hhhour
mmmin
ss.ssssec
Longitude
where:
ddd deg
mm.mmmm
 min(resolution 1E-4)
$GPGGA,hhmmss.sss,ddmm.mmmm,N,dddmm.mmmm,E,
0 2
38 40
48
13
56
23 25
36
v,ss,dd.d,hhhhh.h,M,gggg.g,M,XXX.X,0000*hh<CR><LF>
Latitude
Num of STAs used
range: 00 - 12
State of measuring
where:
0Not working
1Working
Latitude unit in meter
WWest
EEast