├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── asmfunc.S ├── diskio.c ├── main.c ├── pff ├── doc │ ├── 00index_p.html │ ├── css_e.css │ ├── css_p.css │ ├── img │ │ ├── layers3.png │ │ └── rwtest3.png │ └── pf │ │ ├── appnote.html │ │ ├── dinit.html │ │ ├── dreadp.html │ │ ├── dwritep.html │ │ ├── filename.html │ │ ├── lseek.html │ │ ├── mount.html │ │ ├── open.html │ │ ├── opendir.html │ │ ├── read.html │ │ ├── readdir.html │ │ ├── sdir.html │ │ ├── sfatfs.html │ │ ├── sfileinfo.html │ │ └── write.html └── src │ ├── 00readme.txt │ ├── diskio.c │ ├── diskio.h │ ├── integer.h │ ├── pff.c │ ├── pff.h │ └── pffconf.h ├── spi_pins.h └── uart ├── uart.c └── uart.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.eps 3 | *.bak 4 | *.a 5 | *.bin 6 | *.elf 7 | *.hex 8 | *.lst 9 | *.map 10 | /nbproject -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, zevero 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------ 2 | # Makefile for stand-alone MMC boot strap loader 3 | #------------------------------------------------------------------ 4 | # Change these defs for the target device 5 | 6 | MCU_TARGET = atmega1284p # Target device to be used (32K or larger) 7 | BOOT_ADR = 0x1F000 # Boot loader start address [byte] NOT [word] as in http://eleccelerator.com/fusecalc/fusecalc.php?chip=atmega1284p 8 | F_CPU = 16000000 # CPU clock frequency [Hz] NOT critical: it just should be higher than the actual Hz 9 | SD_CS_PORT = PORTB # Data Register of the SD CS pin 10 | SD_CS_DDR = DDRB # Data Direction Register of the SD CS pin 11 | SD_CS_BIT = 4 # Bit of the SD CS pin 12 | USE_LED = 0 # Debug with two (defined in asmfunc.S) 13 | USE_UART = 0 # Debug on Serial. 0 ... deactivate or divider of http://wormfood.net/avrbaudcalc.php for baud rate! 14 | #------------------------------------------------------------------ 15 | ifeq ($(strip $(USE_UART)),0) 16 | CSRC = main.c pff/src/pff.c diskio.c 17 | else 18 | CSRC = main.c pff/src/pff.c diskio.c uart/uart.c 19 | endif 20 | 21 | TARGET = avr_boot 22 | ASRC = asmfunc.S 23 | OPTIMIZE = -Os -mcall-prologues -ffunction-sections -fdata-sections 24 | DEFS = -DBOOT_ADR=$(BOOT_ADR) -DF_CPU=$(F_CPU) -DUSE_LED=$(USE_LED) -DUSE_UART=$(USE_UART) -DSD_CS_PORT=$(SD_CS_PORT) -DSD_CS_DDR=$(SD_CS_DDR) -DSD_CS_BIT=$(SD_CS_BIT) 25 | LIBS = 26 | DEBUG = dwarf-2 27 | 28 | ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs $(DEFS) 29 | ALL_ASFLAGS = -mmcu=$(MCU_TARGET) -I. -x assembler-with-cpp $(ASFLAGS) 30 | CFLAGS = -g$(DEBUG) -Wall $(OPTIMIZE) $(ADDED_CFLAGS) -mmcu=$(MCU_TARGET) -std=c99 $(DEFS) 31 | LDFLAGS = -Wl,-Map,$(TARGET).map -Wl,--gc-sections -Wl,--section-start,.text=$(BOOT_ADR) 32 | OBJ = $(CSRC:.c=.o) $(ASRC:.S=.o) 33 | 34 | CC = avr-gcc 35 | OBJCOPY = avr-objcopy 36 | OBJDUMP = avr-objdump 37 | SIZE = avr-size 38 | 39 | 40 | all: clean $(TARGET).elf lst text bin size 41 | 42 | $(TARGET).elf: $(OBJ) 43 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) 44 | 45 | clean: 46 | rm -rf *.o $(TARGET).elf *.eps *.bak *.a *.bin 47 | rm -rf pff/src/*.o uart/*.o 48 | rm -rf *.lst *.map $(EXTRA_CLEAN_FILES) 49 | rm -rf $(TARGET).hex 50 | 51 | size: $(TARGET).elf 52 | $(SIZE) -C --mcu=$(MCU_TARGET) $(TARGET).elf 53 | 54 | lst: $(TARGET).lst 55 | %.lst: %.elf 56 | $(OBJDUMP) -h -S $< > $@ 57 | 58 | %.o : %.S 59 | $(CC) -c $(ALL_ASFLAGS) $< -o $@ 60 | 61 | text: $(TARGET).hex 62 | %.hex: %.elf 63 | $(OBJCOPY) -j .text -j .data -j .fuse -O ihex $< $@ 64 | # --- make bin just to check size :) 65 | bin: $(TARGET).bin 66 | %.bin: %.hex 67 | $(OBJCOPY) -I ihex -O binary $< $@ 68 | 69 | print-% : ; @echo $* = $($*) #test any var with make print-XXX 70 | 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | avr_boot 2 | ======== 3 | 4 | SD card bootloader for atmega processors 5 | 6 | As easy as it can get! I spent days with this. Hopefully you wont! 7 | 8 | - for any ATMega with 4096kb Bootloader 9 | - uses Petit FatFs R0.03 for FAT12, FAT16, FAT32 10 | - looks for FIRMWARE.BIN and flashes it nearly instantly 11 | - without any interference to your application 12 | - no CRC Check and no version bytes in EEPROM (see KISS) 13 | 14 | ### Boards Manager installation 15 | 16 | avr_boot is integrated in Arduino IDE version 1.6.4 or greater!!! [See here for instructions.](https://github.com/zevero/avr_boot/tree/gh-pages) 17 | 18 | ### Manual installation 19 | 20 | This is with avr-gcc and avrdude under linux with an Atmega1284p and AVRISP mkII! Adaption to your case (WinAvr, another Atmega, another flash-tool) will not be complicated... 21 | 22 | - adapt Makefile 23 | - MCU_TARGET: Your atmegaXXX 24 | - BOOT_ADR: in bytes not words! 25 | - F_CPU: CPU Frequency (not critical. A higher value will work as well) 26 | - SD_CS_PORT: Data Register of the SD CS pin(see the datasheet for your microcontroller) 27 | - SD_CS_DDR: Data Direction Register of the SD CS pin 28 | - SD_CS_BIT: Bit of the SD CS pin 29 | - USE_LED: For debugging 0...deactivate or 1...active 30 | - USE_UART: For debugging 0...deactivate or divider (UBRR) for baudate see http://wormfood.net/avrbaudcalc.php 31 | - update spi_pins.h with the SPI pins of your microcontroller if not already defined 32 | - if using USE_LED adapt LED-pins in asmfunc.S 33 | - if you want to add FAT12 adapt pff/src/pffconfh.h (default ist FAT16 + FAT32) 34 | - if you want to support lower case filenames adapt pff/src/pffconfh.h (default is uppercase) 35 | - if you prefer another filename instead of FIRMWARE.BIN adapt main.c 36 | - make (you may need to do "sudo apt-get install avr-libc gcc-avr") 37 | - set fuses: avrdude -c avrispmkII -p m1284p -U hfuse:w:0xda:m 38 | - find high fuse in http://eleccelerator.com/fusecalc/fusecalc.php?chip=atmega1284p 39 | - flash: avrdude -c avrispmkII -p m1284p -Uflash:w:./avr_boot.hex:i -Ulock:w:0x3F:m 40 | 41 | ### Put your sketch on SD card 42 | 43 | - in Arduino IDE go to File > Preferences and check "Show verbose output during compiliation" 44 | - compile sketch and find the location of your /tmp/buildxxx/sketch.cpp.hex 45 | - make bin file: avr-objcopy -I ihex -O binary sketch.cpp.hex FIRMWARE.BIN 46 | - copy the file into the root of an SD (FAT16/FAT32) 47 | - put it into the SD slot of your ATmega 48 | - reset it 49 | - it might already have happend! 50 | 51 | ### Bootloader sizes 52 | Compiled under linux for atmega328p / atmega1284p 53 | - 3674 / 3724 bytes 54 | - 3984 / 4034 bytes debugging with USE_LED 55 | - 3992 / 4052 bytes debugging with USE_UART 56 | 57 | ### Tested successfully on 58 | - ATmega168 59 | - ATmega328P 60 | - ATmega32u4 61 | - ATmega1284P 62 | - ATmega2560 (see issue #2) 63 | 64 | ### Serial support - Help wanted 65 | it should not be impossible to fit a normal serial bootloader (with automatic baudrate detection?) into the remaining bytes ... help is appreciated! 66 | 67 | ### KISS 68 | If you wish you *can* add CRC Check or versioning with EEPROM *but* I prefere to keep things simple. avr_boot will reflash your FIRMWARE.BIN as long as it is present. 69 | Is this a problem? No! It happens nearly instantly and only differing bytes are flashed really. 70 | You may consider putting your logic into your application and perform a CRC Check after the fact to inform the user and delete or rename FIRMWARE.BIN 71 | 72 | ### Thanks to 73 | - https://github.com/per1234 - Boards Manager Installation and help with differenct MCUs 74 | - http://elm-chan.org/fsw/ff/00index_p.html 75 | - Wilfried Klaas for the MCSDepthLogger https://github.com/willie68/OpenSeaMapLogger 76 | - https://github.com/mharizanov/avr_boot 77 | - https://github.com/osbock/avr_boot 78 | - and others??? 79 | 80 | ### Alternatives 81 | 82 | - https://spaces.atmel.com/gf/project/sdbootloader/ 83 | - https://github.com/thseiler/embedded/tree/master/avr/2boots 84 | - http://www.mikrocontroller.net/articles/MMC/SD_Bootloader_f%C3%BCr_AT_Mega 85 | 86 | ... call me stupid, but I passed several days debugging those - without success ... 87 | -------------------------------------------------------------------------------- /asmfunc.S: -------------------------------------------------------------------------------- 1 | ;---------------------------------------------------------------------------; 2 | ; MMC hardware controls and Flash controls (C)ChaN, 2010 3 | ;---------------------------------------------------------------------------; 4 | ; Hardware dependent macros to be modified //do this in Makefile 5 | #include "spi_pins.h" 6 | 7 | ; ALL Pins given as Port (A,B,C,...) plus number 8 | 9 | ; LED Pins 10 | #define DDR_SS _SFR_IO_ADDR(DDRD), 5 // SS pin (PIN, PORT) 11 | #define PORT_SS _SFR_IO_ADDR(PORTD), 5 12 | 13 | #define DDR_PW _SFR_IO_ADDR(DDRD), 6 // Power pin (PIN, PORT) 14 | #define PORT_PW _SFR_IO_ADDR(PORTD), 6 15 | 16 | ;SD CARD PINS 17 | #define DDR_CS _SFR_IO_ADDR(SD_CS_DDR), SD_CS_BIT 18 | #define PORT_CS _SFR_IO_ADDR(SD_CS_PORT), SD_CS_BIT 19 | 20 | ;---------------------------------------------------------------------------; 21 | .nolist 22 | #include 23 | .list 24 | .text 25 | 26 | .global init_leds 27 | .func init_leds 28 | init_leds: 29 | sbi DDR_SS 30 | sbi DDR_PW 31 | ret 32 | .endfunc 33 | 34 | 35 | .global led_write_on 36 | .func led_write_on 37 | led_write_on: 38 | sbi PORT_SS 39 | ret 40 | .endfunc 41 | 42 | .global led_write_off 43 | .func led_write_off 44 | led_write_off: 45 | cbi PORT_SS 46 | ret 47 | .endfunc 48 | 49 | .global led_power_on 50 | .func led_power_on 51 | led_power_on: 52 | sbi PORT_PW 53 | ret 54 | .endfunc 55 | 56 | .global led_power_off 57 | .func led_power_off 58 | led_power_off: 59 | cbi PORT_PW 60 | ret 61 | .endfunc 62 | 63 | .global led_power_toggle 64 | .func led_power_toggle 65 | led_power_toggle: 66 | sbis PORT_PW 67 | jmp led_power_on 68 | jmp led_power_off 69 | .endfunc 70 | .global led_write_toggle 71 | .func led_write_toggle 72 | led_write_toggle: 73 | sbis PORT_SS 74 | jmp led_write_on 75 | jmp led_write_off 76 | .endfunc 77 | 78 | ;---------------------------------------------------------------------------; 79 | ; Initialize MMC port 80 | ; 81 | ; void init_spi (void); 82 | 83 | .global init_spi 84 | .func init_spi 85 | init_spi: 86 | sbi DDR_CS ; CS: output 87 | sbi DDR_DI ; DI: output 88 | sbi DDR_CK ; SCLK: output 89 | sbi PORT_DO ; DO: pull-up 90 | ret 91 | .endfunc 92 | 93 | 94 | 95 | ;---------------------------------------------------------------------------; 96 | ; Delay 100 microseconds 97 | ; 98 | ; void dly_us (UINT n); 99 | 100 | .global dly_100us 101 | .func dly_100us 102 | dly_100us: 103 | ldi r24, lo8(F_CPU / 100000) /* Loop counter */ 104 | 1: sbiw r30, 1 /* 10 clocks per loop */ 105 | sbiw r30, 1 106 | sbiw r30, 1 107 | nop 108 | dec r24 109 | brne 1b 110 | ret 111 | .endfunc 112 | 113 | 114 | 115 | ;---------------------------------------------------------------------------; 116 | ; Select MMC 117 | ; 118 | ; void select (void); 119 | 120 | .global select 121 | .func select 122 | select: 123 | rcall deselect 124 | cbi PORT_CS 125 | rjmp rcv_spi 126 | .endfunc 127 | 128 | 129 | 130 | ;---------------------------------------------------------------------------; 131 | ; Deselect MMC 132 | ; 133 | ; void deselect (void); 134 | 135 | .global deselect 136 | .func deselect 137 | deselect: 138 | sbi PORT_CS 139 | ; Goto next function 140 | .endfunc 141 | 142 | 143 | 144 | ;---------------------------------------------------------------------------; 145 | ; Receive a byte 146 | ; 147 | ; BYTE rcv_spi (void); 148 | 149 | .global rcv_spi 150 | .func rcv_spi 151 | rcv_spi: 152 | ldi r24, 0xFF ; Send 0xFF to receive data 153 | ; Goto next function 154 | .endfunc 155 | 156 | 157 | 158 | ;---------------------------------------------------------------------------; 159 | ; Transmit a byte 160 | ; 161 | ; void xmit_spi (BYTE); 162 | 163 | .global xmit_spi 164 | .func xmit_spi 165 | xmit_spi: 166 | ldi r25, 8 167 | 1: sbrc r24, 7 ; DI = Bit to sent 168 | sbi PORT_DI ; 169 | sbrs r24, 7 ; 170 | cbi PORT_DI ; / 171 | lsl r24 ; Get DO from MMC 172 | sbic PIN_DO ; 173 | inc r24 ; / 174 | sbi PORT_CK ; A positive pulse to SCLK 175 | cbi PORT_CK ; / 176 | dec r25 ; Repeat 8 times 177 | brne 1b ; / 178 | ret 179 | .endfunc 180 | 181 | 182 | 183 | ;--------------------------------------------------------------------------- 184 | ; Erase a flash page 185 | ; 186 | ; void flash_erase (DWORD flash_addr); 187 | 188 | #ifndef SPMCSR 189 | #define SPMCSR SPMCR 190 | #endif 191 | 192 | .global flash_erase 193 | .func flash_erase 194 | flash_erase: 195 | 196 | movw ZL, r22 197 | #if FLASHEND >= 0x10000 198 | out _SFR_IO_ADDR(RAMPZ), r24 199 | #endif 200 | 201 | ; Initiate erase operation 202 | ldi r24, 0b00000011 203 | sts _SFR_MEM_ADDR(SPMCSR), r24 204 | spm 205 | 206 | ; Wait for end of erase operation 207 | 1: lds r24, _SFR_MEM_ADDR(SPMCSR) 208 | sbrc r24, 0 209 | rjmp 1b 210 | 211 | ; Re-enable read access to the flash 212 | ldi r24, 0b00010001 213 | sts _SFR_MEM_ADDR(SPMCSR), r24 214 | spm 215 | 216 | 9: ret 217 | .endfunc 218 | 219 | 220 | 221 | ;--------------------------------------------------------------------------- 222 | ; Write a flash page 223 | ; 224 | ; void flash_write (DWORD flash_addr, const BYTE* data); 225 | 226 | .global flash_write 227 | .func flash_write 228 | flash_write: 229 | push r0 230 | push r1 231 | 232 | #if FLASHEND >= 0x10000 233 | out _SFR_IO_ADDR(RAMPZ), r24 234 | #endif 235 | 236 | ; Fill page buffer 237 | movw ZL, r22 238 | movw XL, r20 239 | ldi r25, lo8(SPM_PAGESIZE/2) 240 | 1: ld r0, X+ 241 | ld r1, X+ 242 | ldi r24, 0b00000001 243 | sts _SFR_MEM_ADDR(SPMCSR), r24 244 | spm 245 | adiw ZL, 2 246 | dec r25 247 | brne 1b 248 | 249 | ; Initiate write operation 250 | movw ZL, r22 251 | ldi r24, 0b00000101 252 | sts _SFR_MEM_ADDR(SPMCSR), r24 253 | spm 254 | 255 | ; Wait for end of write operation 256 | 2: lds r24, _SFR_MEM_ADDR(SPMCSR) 257 | sbrc r24, 0 258 | rjmp 2b 259 | 260 | ; Re-enable read access to the flash 261 | ldi r24, 0b00010001 262 | sts _SFR_MEM_ADDR(SPMCSR), r24 263 | spm 264 | 265 | 9: pop r1 266 | pop r0 267 | ret 268 | .endfunc 269 | -------------------------------------------------------------------------------- /diskio.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*/ 2 | /* Low level disk I/O module skeleton for Petit FatFs (C)ChaN, 2014 */ 3 | /*-----------------------------------------------------------------------*/ 4 | 5 | #include "pff/src/pff.h" 6 | #include "pff/src/diskio.h" 7 | 8 | void init_spi (void); /* Initialize SPI port (asmfunc.S) */ 9 | void deselect (void); /* Select MMC (asmfunc.S) */ 10 | void select (void); /* Deselect MMC (asmfunc.S) */ 11 | void xmit_spi (BYTE d); /* Send a byte to the MMC (asmfunc.S) */ 12 | BYTE rcv_spi (void); /* Send a 0xFF to the MMC and get the received byte (asmfunc.S) */ 13 | void dly_100us (void); /* Delay 100 microseconds (asmfunc.S) */ 14 | 15 | 16 | 17 | /*-------------------------------------------------------------------------- 18 | 19 | Module Private Functions 20 | 21 | ---------------------------------------------------------------------------*/ 22 | 23 | /* Definitions for MMC/SDC command */ 24 | #define CMD0 (0x40+0) /* GO_IDLE_STATE */ 25 | #define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */ 26 | #define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */ 27 | #define CMD8 (0x40+8) /* SEND_IF_COND */ 28 | #define CMD16 (0x40+16) /* SET_BLOCKLEN */ 29 | #define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */ 30 | #define CMD24 (0x40+24) /* WRITE_BLOCK */ 31 | #define CMD55 (0x40+55) /* APP_CMD */ 32 | #define CMD58 (0x40+58) /* READ_OCR */ 33 | 34 | 35 | /* Card type flags (CardType) */ 36 | #define CT_MMC 0x01 /* MMC ver 3 */ 37 | #define CT_SD1 0x02 /* SD ver 1 */ 38 | #define CT_SD2 0x04 /* SD ver 2 */ 39 | #define CT_BLOCK 0x08 /* Block addressing */ 40 | 41 | 42 | static 43 | BYTE CardType; 44 | 45 | 46 | /*-----------------------------------------------------------------------*/ 47 | /* Send a command packet to MMC */ 48 | /*-----------------------------------------------------------------------*/ 49 | 50 | static 51 | BYTE send_cmd ( 52 | BYTE cmd, /* 1st byte (Start + Index) */ 53 | DWORD arg /* Argument (32 bits) */ 54 | ) 55 | { 56 | BYTE n, res; 57 | 58 | 59 | if (cmd & 0x80) { /* ACMD is the command sequense of CMD55-CMD */ 60 | cmd &= 0x7F; 61 | res = send_cmd(CMD55, 0); 62 | if (res > 1) return res; 63 | } 64 | 65 | /* Select the card */ 66 | select(); 67 | 68 | /* Send a command packet */ 69 | xmit_spi(cmd); /* Start + Command index */ 70 | xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */ 71 | xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */ 72 | xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */ 73 | xmit_spi((BYTE)arg); /* Argument[7..0] */ 74 | n = 0x01; /* Dummy CRC + Stop */ 75 | if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */ 76 | if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */ 77 | xmit_spi(n); 78 | 79 | /* Receive a command response */ 80 | n = 10; /* Wait for a valid response in timeout of 10 attempts */ 81 | do { 82 | res = rcv_spi(); 83 | } while ((res & 0x80) && --n); 84 | 85 | return res; /* Return with the response value */ 86 | } 87 | 88 | 89 | 90 | 91 | /*-------------------------------------------------------------------------- 92 | 93 | Public Functions 94 | 95 | ---------------------------------------------------------------------------*/ 96 | /*-----------------------------------------------------------------------*/ 97 | /* Initialize Disk Drive */ 98 | /*-----------------------------------------------------------------------*/ 99 | 100 | DSTATUS disk_initialize (void) 101 | { 102 | DSTATUS stat; 103 | 104 | BYTE n, cmd, ty, ocr[4]; 105 | UINT tmr; 106 | 107 | 108 | init_spi(); /* Initialize ports to control MMC */ 109 | for (n = 100; n; n--) dly_100us(); /* 10ms delay */ 110 | for (n = 10; n; n--) deselect(); /* 80 Dummy clocks with CS=H */ 111 | 112 | ty = 0; 113 | if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ 114 | if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2 */ 115 | for (n = 0; n < 4; n++) ocr[n] = rcv_spi(); /* Get trailing return value of R7 resp */ 116 | if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ 117 | for (tmr = 10000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) dly_100us(); /* Wait for leaving idle state (ACMD41 with HCS bit) */ 118 | if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ 119 | for (n = 0; n < 4; n++) ocr[n] = rcv_spi(); 120 | ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */ 121 | } 122 | } 123 | } else { /* SDv1 or MMCv3 */ 124 | if (send_cmd(ACMD41, 0) <= 1) { 125 | ty = CT_SD1; cmd = ACMD41; /* SDv1 */ 126 | } else { 127 | ty = CT_MMC; cmd = CMD1; /* MMCv3 */ 128 | } 129 | for (tmr = 10000; tmr && send_cmd(cmd, 0); tmr--) dly_100us(); /* Wait for leaving idle state */ 130 | if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ 131 | ty = 0; 132 | } 133 | } 134 | CardType = ty; 135 | deselect(); 136 | 137 | stat = ty ? 0 : STA_NOINIT; 138 | 139 | return stat; 140 | } 141 | 142 | 143 | 144 | /*-----------------------------------------------------------------------*/ 145 | /* Read Partial Sector */ 146 | /*-----------------------------------------------------------------------*/ 147 | 148 | DRESULT disk_readp ( 149 | BYTE* buff, /* Pointer to the destination object */ 150 | DWORD sector, /* Sector number (LBA) */ 151 | UINT offset, /* Offset in the sector */ 152 | UINT count /* Byte count (bit15:destination) */ 153 | ) 154 | { 155 | DRESULT res; 156 | BYTE rc; 157 | WORD bc; 158 | 159 | if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ 160 | 161 | res = RES_ERROR; 162 | if (send_cmd(CMD17, sector) == 0) { /* READ_SINGLE_BLOCK */ 163 | 164 | bc = 40000; 165 | do { /* Wait for data packet */ 166 | rc = rcv_spi(); 167 | } while (rc == 0xFF && --bc); 168 | 169 | if (rc == 0xFE) { /* A data packet arrived */ 170 | bc = 514 - offset - count; 171 | 172 | /* Skip leading bytes */ 173 | if (offset) { 174 | do rcv_spi(); while (--offset); 175 | } 176 | 177 | /* Receive a part of the sector */ 178 | do { 179 | *buff++ = rcv_spi(); 180 | } while (--count); 181 | 182 | /* Skip trailing bytes and CRC */ 183 | do rcv_spi(); while (--bc); 184 | 185 | res = RES_OK; 186 | } 187 | } 188 | 189 | deselect(); 190 | 191 | return res; 192 | } 193 | 194 | 195 | 196 | /*-----------------------------------------------------------------------*/ 197 | /* Write Partial Sector */ 198 | /*-----------------------------------------------------------------------*/ 199 | /* 200 | DRESULT disk_writep ( 201 | const BYTE* buff, // Pointer to the data to be written, NULL:Initiate/Finalize write operation 202 | DWORD sc // Sector number (LBA) or Number of bytes to send 203 | ) 204 | { 205 | DRESULT res; 206 | 207 | 208 | if (!buff) { 209 | if (sc) { 210 | 211 | // Initiate write process 212 | 213 | } else { 214 | 215 | // Finalize write process 216 | 217 | } 218 | } else { 219 | 220 | // Send data to the disk 221 | 222 | } 223 | 224 | return res; 225 | } 226 | */ 227 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------/ 2 | / Stand-alone MMC boot loader R0.01 3 | /--------------------------------------------------------------------------/ 4 | / 5 | / Copyright (C) 2010, ChaN, all right reserved. 6 | / 7 | / * This software is a free software and there is NO WARRANTY. 8 | / * No restriction on use. You can use, modify and redistribute it for 9 | / personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. 10 | / * Redistributions of source code must retain the above copyright notice. 11 | / 12 | /--------------------------------------------------------------------------/ 13 | / Dec 6, 2010 R0.01 First release 14 | /--------------------------------------------------------------------------/ 15 | / This is a stand-alone MMC/SD boot loader for megaAVRs. It requires a 4KB 16 | / boot section for code, four GPIO pins for MMC/SD as shown in sch.jpg and 17 | / nothing else. To port the boot loader into your project, follow the 18 | / instruction sdescribed below. 19 | / 20 | / 1. Setup the hardware. Attach a memory card socket to the any GPIO port 21 | / where you like. Select boot size at least 4KB for the boot loader with 22 | / BOOTSZ fuses and enable boot loader with BOOTRST fuse. 23 | / 24 | / 2. Setup the software. Change the four port definitions in the asmfunc.S. 25 | / Change MCU_TARGET, BOOT_ADR and MCU_FREQ in the Makefile. The BOOT_ADR 26 | / is a BYTE address of boot section in the flash. Build the boot loader 27 | / and write it to the device with a programmer. 28 | / 29 | / 3. Build the application program and output it in binary form instead of 30 | / hex format. Rename the file "app.bin" and put it into the memory card. 31 | / 32 | / 4. Insert the card and turn the target power on. When the boot loader found 33 | / the application file, the file is written into the flash memory prior to 34 | / start the application program. On-board LED lights (if exist) during 35 | / the flash programming operation. 36 | / 37 | /-------------------------------------------------------------------------*/ 38 | 39 | const char filename[13] ="FIRMWARE.BIN\0"; // EDIT FILENAME HERE 40 | #include //Watchdog 41 | // The following code is recommended in http://avr-libc.nongnu.org/user-manual/group__avr__watchdog.html but is disabled for now because avr_boot doesn't currently do anything with mcusr_mirror so for now we will only reset MCUSR and disable WDT. 42 | //uint8_t mcusr_mirror __attribute__ ((section (".noinit")));void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3")));void get_mcusr(void){mcusr_mirror = MCUSR;MCUSR = 0;wdt_disable();} 43 | void disable_watchdog(void) __attribute__((naked)) __attribute__((section(".init3"))); 44 | void disable_watchdog(void) 45 | { 46 | #if defined(MCUCSR) 47 | MCUCSR = ~(_BV(WDRF)); //Some MCUs require the watchdog reset flag to be cleared before WDT can be disabled. & operation is skipped to spare few bytes as bits in MCUSR can only be cleared. 48 | #else 49 | MCUSR = ~(_BV(WDRF)); //Some MCUs require the watchdog reset flag to be cleared before WDT can be disabled. & operation is skipped to spare few bytes as bits in MCUSR can only be cleared. 50 | #endif 51 | wdt_disable(); //immediately disable watchdog in case it was running in the application to avoid perpetual reset loop 52 | } 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include "pff/src/pff.h" 59 | 60 | 61 | #if BOOT_ADR > 0xFFFF 62 | #define PGM_READ_BYTE(x) pgm_read_byte_far(x) 63 | #else 64 | #define PGM_READ_BYTE(x) pgm_read_byte(x) 65 | #endif 66 | 67 | #if USE_UART 68 | #include "uart/uart.h" 69 | #endif 70 | 71 | #if USE_LED 72 | void init_leds(); 73 | void led_power_on(); 74 | void led_power_off(); 75 | void led_power_toggle(); 76 | void led_write_on(); 77 | void led_write_off(); 78 | void led_write_toggle(); 79 | #endif 80 | void flash_erase (DWORD); /* Erase a flash page (asmfunc.S) */ 81 | void flash_write (DWORD, const BYTE*); /* Program a flash page (asmfunc.S) */ 82 | 83 | 84 | FATFS Fatfs; // Petit-FatFs work area 85 | BYTE Buff[SPM_PAGESIZE]; // Page data buffer 86 | 87 | 88 | 89 | static uint8_t pagecmp(const DWORD fa, uint8_t buff[SPM_PAGESIZE]) 90 | { 91 | UINT i; 92 | uint8_t b_flash,b_buff; 93 | for (i = 0; i < SPM_PAGESIZE; i++) { 94 | b_flash = PGM_READ_BYTE(fa+i); 95 | b_buff = buff[i]; 96 | if ( b_flash != b_buff) { 97 | #if USE_UART //output first difference 98 | UART_puthex32(fa);UART_puts(PSTR(":")); 99 | UART_puthex(b_flash);UART_puts(PSTR(" ")); 100 | UART_puthex(b_buff); UART_newline(); 101 | #endif 102 | return 1; 103 | } 104 | } 105 | #if USE_UART //output first difference 106 | UART_puthex32(fa);UART_puts(PSTR(":")); 107 | UART_puts(PSTR("="));UART_newline(); 108 | #endif 109 | return 0; 110 | } 111 | 112 | void doFlash() { 113 | DWORD fa; /* Flash address */ 114 | UINT br; /* Bytes read */ 115 | #if USE_LED 116 | uint8_t i; 117 | for(i=0;i<50;i++) { led_write_toggle();_delay_ms(100);} //Start Programming: Flash WRITE Wildly for 5 secs 118 | #endif 119 | 120 | 121 | for (fa = 0; fa < BOOT_ADR; fa += SPM_PAGESIZE) { /* Update all application pages */ 122 | 123 | memset(Buff, 0xFF, SPM_PAGESIZE); /* Clear buffer */ 124 | pf_read(Buff, SPM_PAGESIZE, &br); /* Load a page data */ 125 | 126 | if (pagecmp(fa, Buff)) { /* Only flash if page is changed */ 127 | #if USE_LED 128 | led_write_off(); 129 | led_power_on(); 130 | #endif 131 | flash_erase(fa); /* Erase a page */ 132 | flash_write(fa, Buff); /* Write it if the data is available */ 133 | 134 | } else { 135 | 136 | #if USE_LED 137 | led_power_off(); 138 | led_write_on(); 139 | #endif 140 | } 141 | } 142 | } 143 | 144 | void checkFile() { 145 | uint8_t fresult; 146 | 147 | fresult = pf_mount(&Fatfs); /* Initialize file system */ 148 | 149 | if (fresult != FR_OK) { /* File System could not be mounted */ 150 | #if USE_UART 151 | UART_puts(PSTR("File not mounted")); 152 | UART_newline(); 153 | #endif 154 | 155 | #if USE_LED 156 | uint8_t i; 157 | led_write_on(); 158 | for(i=0;i<2*fresult;i++) { led_power_toggle();_delay_ms(500);}//Give error number while Write led is on 159 | led_write_off(); 160 | #endif 161 | return; 162 | } 163 | /* 164 | 165 | WORD flashver = eeprom_read_word((const uint16_t *)E2END - 1); 166 | if (flashver > 999) { 167 | flashver = 0; 168 | } 169 | BYTE y, tmp; 170 | WORD x; 171 | BYTE found = 0; 172 | 173 | for (x = flashver+10; x > flashver; x--) { 174 | y = x / 100; 175 | filename[5] = y + 0x30; 176 | tmp = x % 100; 177 | 178 | y = tmp / 10; 179 | filename[6] = y + 0x30; 180 | tmp = x % 10; 181 | 182 | filename[7] = tmp + 0x30; 183 | 184 | if (pf_open(filename) == FR_OK) { // File opens normally 185 | found = 1; 186 | doProgram(); 187 | } 188 | led_power_toggle(); 189 | } 190 | 191 | if (found == 0) {*/ 192 | 193 | fresult = pf_open(filename); 194 | 195 | if (fresult != FR_OK) { /* File could not be opened */ 196 | 197 | #if USE_UART 198 | UART_puts(PSTR("File not open")); 199 | UART_newline(); 200 | #endif 201 | #if USE_LED 202 | uint8_t i; 203 | led_power_on(); 204 | for(i=0;i<2*fresult;i++) { led_write_toggle();_delay_ms(500);}//Give error number while Power led is on 205 | led_power_off(); 206 | #endif 207 | return; 208 | } 209 | 210 | doFlash(); 211 | 212 | #if USE_LED 213 | led_write_off(); 214 | led_power_off(); 215 | _delay_ms(2000); 216 | uint8_t i; 217 | for(i=0;i<40;i++) { led_power_toggle();_delay_ms(50);}//SUCCESS FLASH WILDLY for 2 secs 218 | #endif 219 | 220 | } 221 | 222 | 223 | 224 | 225 | 226 | 227 | int main (void) 228 | { 229 | #if USE_LED 230 | init_leds(); 231 | uint8_t i=0; 232 | #endif 233 | 234 | #if USE_UART 235 | UART_init(); 236 | UART_puts(PSTR("AVR_BOOT")); 237 | UART_newline(); 238 | #endif 239 | while (1) { 240 | #if USE_LED 241 | led_power_on();_delay_ms(200);led_power_off(); //Test Power Led 242 | led_write_on();_delay_ms(200);led_write_off(); //Test Write Led 243 | #endif 244 | 245 | checkFile(); 246 | 247 | if (pgm_read_word(0) != 0xFFFF) ((void(*)(void))0)(); //EXIT BOOTLOADER 248 | 249 | #if USE_UART 250 | UART_puts(PSTR("retry")); 251 | UART_newline(); 252 | #endif 253 | #if USE_LED 254 | for(i=0;i<10;i++) { led_power_toggle();_delay_ms(200);} //SOMETHING WENT WRONG: Flash Power LED 255 | #endif 256 | _delay_ms(5000); // Retry 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /pff/doc/00index_p.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Petit FAT File System Module 13 | 14 | 15 | 16 |

Petit FAT File System Module

17 |
18 | 19 |
20 | layer 21 |

Petit FatFs is a sub-set of FatFs module for tiny 8-bit microcontrollers. It is written in compliance with ANSI C and completely separated from the disk I/O layer. It can be incorporated into the tiny microcontrollers with limited memory even if the RAM size is less than sector size. Also full featured FAT file system module is available here↗.

22 | 23 |

Features

24 |
    25 |
  • Very small RAM consumption (44 bytes work area + certain stack).
  • 26 |
  • Very small code size (2K-4K bytes).
  • 27 |
  • FAT12, FAT16 and FAT32.
  • 28 |
  • Single volume and Single file.
  • 29 |
  • File write function with some restrictions.
  • 30 |
31 |
32 | 33 | 34 |
35 |

Application Interface

36 |

Petit FatFs module provides following functions.

37 | 46 |
47 | 48 | 49 |
50 |

Disk I/O Interface

51 |

Since the Petit FatFs module is completely separated from disk I/O layer, it requires following functions to lower layer to read data from storage device. The low level disk I/O module is not a part of Petit FatFs module and it must be provided by user. The sample drivers are also available in the resources.

52 | 57 |
58 | 59 | 60 |
61 |

Resources

62 |

The Petit FatFs module is a free software and is opened for education, research and development. You can use, modify and/or redistribute it for personal, non-profit or commercial use without any restriction under your responsibility. For further information, refer to the application note.

63 | 71 |
72 | 73 | 74 |
75 |

Return

76 | 77 | 78 | -------------------------------------------------------------------------------- /pff/doc/css_e.css: -------------------------------------------------------------------------------- 1 | * {margin: 0; padding: 0; border-width: 0;} 2 | body {margin: 8px; background-color: #e0ffff; font-color: black; font-family: serif; line-height: 133%; max-width: 1024px;} 3 | a:link {color: blue;} 4 | a:visited {color: darkmagenta;} 5 | a:hover {background-color: #a0ffff;} 6 | a:active {color: darkmagenta; overflow: hidden; outline:none; position: relative; top: 1px; left: 1px;} 7 | abbr {border-width: 1px;} 8 | 9 | p {margin: 0 0 0.3em 1em;} 10 | i {margin: 0 0.3em 0 0;} 11 | b {margin: 0 0.1em;} 12 | em {font-style: normal; font-weight: bold; margin: 0 0.1em;} 13 | strong {} 14 | pre {border: 1px dashed gray; margin: 0.5em 1em; padding: 0.5em; line-height: 1.2em; font-size: 85%; font-family: "Consolas", "Courier New", monospace; background-color: white;} 15 | pre span.c {color: green;} 16 | pre span.k {color: blue;} 17 | pre span.arg {font-style: italic;} 18 | tt {margin: 0 0.2em; font-size: 0.85em; font-family: "Consolas", "Courier New", monospace; } 19 | tt.arg {font-style: italic;} 20 | ol {margin: 0.5em 2.5em;} 21 | ul {margin: 0.5em 2em;} 22 | dl {margin: 0.5em 1em;} 23 | dd {margin: 0 2em;} 24 | dt {font-size: 0.85em; font-family: "Consolas", "Courier New", monospace;} 25 | dl.par dt {margin: 0.5em 0 0 0 ; font-style: italic; } 26 | dl.ret dt {margin: 0.5em 0 0 0 ; font-size: 0.85em; font-family: "Consolas", "Courier New", monospace;} 27 | hr {border-width: 1px; margin: 1em;} 28 | div.abst {font-family: sans-serif;} 29 | div.para {clear: both; font-family: serif;} 30 | div.ret a {font-size: 0.85em; font-family: "Consolas", "Courier New", monospace; } 31 | .equ {text-indent: 0; margin: 1em 2em 1em;} 32 | .indent {margin-left: 2em;} 33 | .rset {float: right; margin: 0.3em 0 0.5em 0.5em;} 34 | .lset {float: left; margin: 0.3em 0.5em 0.5em 0.5em;} 35 | ul.flat li {list-style-type: none; margin: 0;} 36 | a.imglnk img {border: 1px solid;} 37 | .iequ {white-space: nowrap; font-weight: bold;} 38 | .clr {clear: both;} 39 | .it {font-style: italic;} 40 | .mfd {font-size: 0.7em; padding: 0 1px; border: 1px solid; white-space : nowrap} 41 | .ral {text-align: right; } 42 | .lal {text-align: left; } 43 | .cal {text-align: center; } 44 | 45 | h1 {line-height: 1em; font-size: 2em; font-family: sans-serif; padding: 0.3em 0 0.3em;} 46 | p.hdd {float: right; text-align: right; margin-top: 0.5em;} 47 | hr.hds {clear: both; margin-bottom: 1em;} 48 | 49 | h2 {font-size: 2em; font-family: sans-serif; background-color: #d8d8FF; padding: 0.5em 0.5em; margin: 0 0 0.5em;} 50 | h3 {font-size: 1.5em; font-family: sans-serif; margin: 1.5em 0 0.5em;} 51 | h4 {font-size: 1.2em; font-family: sans-serif; margin: 1em 0 0.2em;} 52 | h5 {font-size: 1em; font-family: sans-serif; margin: 0.5em 0 0em;} 53 | small {font-size: 80%;} 54 | .indent {margin-left: 2em;} 55 | 56 | /* Tables */ 57 | table {margin: 0.5em 1em; border-collapse: collapse; border: 2px solid black; } 58 | th {background-color: white; border-style: solid; border-width: 1px 1px 2px; border-color: black; padding: 0 3px; vertical-align: top; white-space: nowrap;} 59 | td {background-color: white; border: 1px solid black; padding: 0 3px; vertical-align: top; line-height: 1.3em;} 60 | table.lst td:first-child {font-size: 0.85em; font-family: "Consolas", "Courier New", monospace;} 61 | table.lst2 td {font-size: 0.85em; font-family: "Consolas", "Courier New", monospace;} 62 | table caption {font-family: sans-serif; font-weight: bold;} 63 | tr.lst3 td { border-width: 2px 1px 1px; } 64 | 65 | p.foot {clear: both; text-indent: 0; margin: 1em 0.5em 1em;} 66 | -------------------------------------------------------------------------------- /pff/doc/css_p.css: -------------------------------------------------------------------------------- 1 | body {margin: 8px; background-color: #ffecf0; font-color: black; font-family: serif; line-height: 133%; max-width: 1024px;} 2 | -------------------------------------------------------------------------------- /pff/doc/img/layers3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zevero/avr_boot/25d588a2c582011069268fb5d55da099f01c00ca/pff/doc/img/layers3.png -------------------------------------------------------------------------------- /pff/doc/img/rwtest3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zevero/avr_boot/25d588a2c582011069268fb5d55da099f01c00ca/pff/doc/img/rwtest3.png -------------------------------------------------------------------------------- /pff/doc/pf/appnote.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | FatFs Module Application Note 10 | 11 | 12 | 13 |

Petit FatFs Module Application Note

14 |
15 | 16 |

Basic Considerations

17 |

The FatFs module is assuming following conditions on portability.

18 |
    19 |
  • ANSI C
    20 | The FatFs module is a middleware written in ANSI C (C89). There is no platform dependence, so long as the compiler is in compliance with ANSI C.
  • 21 |
  • Size of integer types
    22 | The FatFs module assumes that size of char/short/long are 8/16/32 bit and int is 16 or 32 bit. These correspondence are defined in integer.h. This will not be a problem on most compilers. When any conflict with existing definitions is occured, you must resolve it with care.
  • 23 |
24 | 25 | 26 |
27 |

Memory Usage (R0.03)

28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
AVRx86
Compilergcc(WinAVR)VC6
_WORD_ACCESS11
Code (default)21001720
Code (!_USE_READ)-444-246
Code (_USE_DIR)+1002+420
Code (_USE_LSEEK)+490+228
Code (_USE_WRITE)+518+351
RAM (bss)24
RAM (work)4244
40 |

This is the size of the Petit FatFs module itself. In addition to this, a low level disk I/O module will be required for a complete function. The size of MMC/SDC module on AVR becomes approximate 620 bytes without write function and 840 bytes with write function.

41 |
42 | 43 |
44 |

Module Size Reduction

45 |

Follwing table shows which function is removed by configuration options for the module size reduction.

46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
Function_USE_READ_USE_DIR_USE_LSEEK_USE_WRITE
0000
pf_mount
pf_open
pf_readx
pf_lseekx
pf_opendirx
pf_readdirx
pf_writex
57 |
58 | 59 |
60 |

Performance effective file access

61 |

For good performance on reading a file on the small embedded system, application programmer should consider what process is done in the file system module.

62 |

The Petit FatFs reads the disk sectors without a sector buffer. This means the file system reads a part of the sector contains the required data every reference point even if they are in the same sector. However the generic storage device are not byte addressable so that the disk I/O layer will read the entire sector and pick up the data bytes from the read data steram.

63 |

When read 512 byte data from a file at a time, the data sector will be read only a time. When read that data in byte-by-byte, the data sector will be read 512 times. Therefore the byte-by-byte read request will drastically decrease the read performance. To avoid this stupid read controls, the file data should be read in long block as possible. Sector alignment access is not impotant on the Petit FatFs.

64 |

The tiny microcontrollers targeted by Petit FatFs has a limited size of RAM. It may not able to allocate a certain size of read buffer and most type of text processing will require byte-by-byte read operation. The Petit FatFs supports data forwarding feature for such purpose.

65 | 66 |
67 | 68 |
69 |

About FatFs License

70 |

Petit FatFs has being developped as a personal project of author, ChaN. It is free from the code anyone else wrote. Following code block shows a copy of the license document that included in the source files.

71 |
/*----------------------------------------------------------------------------/
72 | /  Petit FatFs - FAT file system module  R0.03                  (C)ChaN, 2014
73 | /-----------------------------------------------------------------------------/
74 | / Petit FatFs module is a generic FAT file system module for small embedded
75 | / systems. This is a free software that opened for education, research and
76 | / commercial developments under license policy of following trems.
77 | /
78 | /  Copyright (C) 2014, ChaN, all right reserved.
79 | /
80 | / * The Petit FatFs module is a free software and there is NO WARRANTY.
81 | / * No restriction on use. You can use, modify and redistribute it for
82 | /   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
83 | / * Redistributions of source code must retain the above copyright notice.
84 | /
85 | /-----------------------------------------------------------------------------/
86 |

Therefore FatFs license is one of the BSD-style licenses but there is a significant feature. Because FatFs is for embedded projects, the conditions of redistributions in binary form, such as embedded code, hex file, binary library and any form without source code, are not specified in order to extend usability to commercial use. The documentation of the distributions need not include about Petit FatFs and its license document, and it may also. This is equivalent to the BSD 1-Clause License. Of course Petit FatFs is compatible with the projects under GNU GPL. When redistribute the Petit FatFs with any modification, the license can also be changed to GNU GPL or BSD-style license.

87 |
88 | 89 |

Return

90 | 91 | 92 | -------------------------------------------------------------------------------- /pff/doc/pf/dinit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - disk_initialize 10 | 11 | 12 | 13 | 14 |
15 |

disk_initialize

16 |

The disk_initialize function initializes the disk drive.

17 |
18 | DSTATUS disk_initialize (void)
19 | 
20 |
21 | 22 |
23 |

Return Values

24 |

The disk status is returned in combination of following flags.

25 |
26 |
STA_NOINIT
27 |
Indicates that the disk drive has not been initialized. This flag is set on: system reset, disk removal and disk_initialize function failed, and cleared on: disk_initialize function succeeded.
28 |
STA_NODISK
29 |
Indicates that no medium in the drive. This is always cleared on fixed disk drive. This flag is not referred by Petit FatFs.
30 |
31 |
32 | 33 |
34 |

Description

35 |

The disk_initialize function initializes the storage device. If the function succeeded, STA_NOINIT flag in the return value is cleared.

36 |
37 | 38 |

Return

39 | 40 | 41 | -------------------------------------------------------------------------------- /pff/doc/pf/dreadp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - disk_readp 10 | 11 | 12 | 13 | 14 |
15 |

disk_readp

16 |

The disk_readp function reads a partial sector of the device.

17 |
18 | DRESULT disk_readp (
19 |   BYTE* buff,    /* [OUT] Pointer to the read buffer */
20 |   DWORD sector,  /* [IN]  Sector number */
21 |   UINT offset,   /* [IN]  Byte offset in the sector to start to read */
22 |   UINT count     /* [IN]  Number of bytes to read */
23 | );
24 | 
25 |
26 | 27 |
28 |

Parameters

29 |
30 |
buff
31 |
Pointer to the read buffer to store the read data. If a NULL is given, read bytes will be forwarded to the outgoing stream instead of the memory.
32 |
sector
33 |
Specifies the sector number to be read in logical block address (LBA).
34 |
offset
35 |
Specifies the byte offset in the sector to start to read. The value can be 0 to 511.
36 |
count
37 |
Specifies number of bytes to read. The value can be 0 to 512 and offset + count must not exceed 512.
38 |
39 |
40 | 41 | 42 |
43 |

Return Value

44 |
45 |
RES_OK (0)
46 |
The function succeeded.
47 |
RES_ERROR
48 |
Any hard error occured during the disk read operation and could not recover it.
49 |
RES_PARERR
50 |
Invalid parameter.
51 |
RES_NOTRDY
52 |
The device has not been initialized.
53 |
54 |
55 | 56 | 57 |

Return

58 | 59 | 60 | -------------------------------------------------------------------------------- /pff/doc/pf/dwritep.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - disk_writep 10 | 11 | 12 | 13 | 14 |
15 |

disk_writep

16 |

The disk_writep function writes data to the sector.

17 |
18 | DRESULT disk_writep (
19 |   BYTE* buff,  /* [IN] Pointer to the data to be written */
20 |   DWORD sc,    /* [IN] Sector number or Number of bytes to wtite */
21 | );
22 | 
23 |
24 | 25 |
26 |

Parameters

27 |
28 |
buff
29 |
Pointer to the data to be written to the sector. If a NULL is given, the function initiate/finalize a write transaction to the sector.
30 |
sc
31 |
Specifies nubmer of bytes to write if buff is not a NULL. If buff is a NULL and sc is not a zero, the function initiates a write transactin to the sector. If buff and sc are zero, the function finalize the current sector write transactin.
32 |
33 |
34 | 35 | 36 |
37 |

Return Value

38 |
39 |
RES_OK (0)
40 |
The function succeeded.
41 |
RES_ERROR
42 |
Any hard error occured during the write operation and could not recover it or the medium is write protected.
43 |
RES_PARERR
44 |
Invalid parameter.
45 |
RES_NOTRDY
46 |
The device has not been initialized.
47 |
48 |
49 | 50 | 51 |
52 |

Description

53 |

A sector write operation is done in following sequence.

54 |
    55 |
  1. disk_writep(0, sector_number); Initiate a sector write transaction.
  2. 56 |
  3. disk_writep(data, byte_to_write); Start to write data to the sector.
  4. 57 |
  5. disk_writep(data, byte_to_write); And data can be written upto 512 bytes with one or more calls.
  6. 58 |
  7. disk_writep(data, byte_to_write); ...
  8. 59 |
  9. disk_writep(0, 0); Finalize the write transaction. If number of bytes sent is less than 512, left bytes in the sector is filled by zero.
  10. 60 |
61 |

If a write transaction is in progress, disk_readp() function will fail and disk_initialize() function finalize the current write transaction.

62 |
63 | 64 | 65 |
66 |

Remarks

67 |

This funciton is needed when _USE_WRITE == 1.

68 |
69 | 70 | 71 |

Return

72 | 73 | 74 | -------------------------------------------------------------------------------- /pff/doc/pf/filename.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - Path Names 10 | 11 | 12 | 13 | 14 |
15 |

Format of the path names

16 |

The path name format on the Petit FatFs module is similer to MS-DOS as follows.

17 |
"[/]directory/file"
18 |

The Petit FatFs module supports only 8.3 format file name. The sub-directories are separated with a /. The path name is terminated with a nul character, control character or white space. Heading spaces are ignored and skipped. When _USE_LCC == 1, lower case characters are allowed for the path name.

19 |

The Petit FatFs module does not have a concept of current directory like OS oriented file system. All objects on the volume are always specified in full path name following from the root directory. Heading separator is ignored and it can be exist or omitted.

20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /pff/doc/pf/lseek.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - pf_lseek 10 | 11 | 12 | 13 | 14 |
15 |

pf_lseek

16 |

The pf_lseek function moves the file read/write pointer of the open file.

17 | 18 |
19 | FRESULT pf_lseek (
20 |   DWORD ofs       /* [IN] File offset in unit of byte */
21 | );
22 | 
23 |
24 | 25 |
26 |

Parameters

27 |
28 |
ofs
29 |
Number of bytes where from start of the file
30 |
31 |
32 | 33 | 34 |
35 |

Return Values

36 |
37 |
FR_OK (0)
38 |
The function succeeded.
39 |
FR_DISK_ERR
40 |
The function failed due to an error in the disk function, a wrong FAT structure or an internal error.
41 |
FR_NOT_OPENED
42 |
The file has not been opened.
43 |
44 |
45 | 46 | 47 |
48 |

Description

49 |

The pf_lseek() function moves the file read/write pointer of the open file. The offset can be specified in only origin from top of the file.

50 |
51 | 52 | 53 |
54 |

Example

55 |
56 |     /* Move to offset of 5000 from top of the file */
57 |     res = pf_lseek(5000);
58 | 
59 |     /* Forward 3000 bytes */
60 |     res = pf_lseek(fs.fptr + 3000);
61 | 
62 |     /* Rewind 2000 bytes (take care on wraparound) */
63 |     res = pf_lseek(fs.fptr - 2000);
64 | 
65 |
66 | 67 |
68 |

QuickInfo

69 |

Available when _USE_LSEEK == 1.

70 |
71 | 72 |
73 |

References

74 |

pf_open, FATFS

75 |
76 | 77 |

Return

78 | 79 | 80 | -------------------------------------------------------------------------------- /pff/doc/pf/mount.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - pf_mount 10 | 11 | 12 | 13 | 14 |
15 |

pf_mount

16 |

The pf_mount fucntion mounts a volume.

17 |
18 | FRESULT pf_mount (
19 |   FATFS*  fs  /* [IN] Pointer to the work area */
20 | );
21 | 
22 |
23 | 24 |
25 |

Parameters

26 |
27 |
fs
28 |
Pointer to the work area (file system object) to be registered.
29 |
30 |
31 | 32 |
33 |

Return Values

34 |
35 |
FR_OK (0)
36 |
The function succeeded.
37 |
FR_NOT_READY
38 |
The drive could not be initialized due to a disk error or no medium.
39 |
FR_DISK_ERR
40 |
An error occured in the disk function.
41 |
FR_NO_FILESYSTEM
42 |
There is no valid FAT partition on the disk.
43 |
44 |
45 | 46 | 47 |
48 |

Description

49 |

The pf_mount() function registers a work area to the Petit FatFs module. The volume is mounted on registration. The volume must be mounted with this function prior to any other file function and after every media changes.

50 |
51 | 52 | 53 |
54 |

QuickInfo

55 |

Always available.

56 |
57 | 58 |
59 |

References

60 |

FATFS

61 |
62 | 63 |

Return

64 | 65 | 66 | -------------------------------------------------------------------------------- /pff/doc/pf/open.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - pf_open 10 | 11 | 12 | 13 | 14 |
15 |

pf_open

16 |

The pf_open function opens an existing file.

17 |
 18 | FRESULT pf_open (
 19 |   const char* path  /* [IN] Pointer to the file neme */
 20 | );
 21 | 
22 |
23 | 24 |
25 |

Parameters

26 |
27 |
path
28 |
Pointer to a null-terminated string that specifies the file name to open.
29 |
30 |
31 | 32 | 33 |
34 |

Return Values

35 |
36 |
FR_OK (0)
37 |
The function succeeded.
38 |
FR_NO_FILE
39 |
Could not find the file or path.
40 |
FR_DISK_ERR
41 |
The function failed due to a hard error in the disk function, a wrong FAT structure or an internal error.
42 |
FR_NOT_ENABLED
43 |
The volume has not been mounted.
44 |
45 |
46 | 47 | 48 |
49 |

Description

50 |

The file must be opend prior to use pf_read() and pf_lseek() function. The open file is valid until next open.

51 |
52 | 53 | 54 |
55 |

Example

56 |
 57 | int main (void)
 58 | {
 59 |     FATFS fs;          /* Work area (file system object) for the volume */
 60 |     BYTE buff[16];     /* File read buffer */
 61 |     UINT br;           /* File read count */
 62 |     FRESULT res;       /* Petit FatFs function common result code */
 63 | 
 64 | 
 65 |     /* Mount the volume */
 66 |     pf_mount(&fs);
 67 |     if (res) die(res);
 68 | 
 69 |     /* Open a file */
 70 |     res = pf_open("srcfile.dat");
 71 |     if (res) die(res);
 72 | 
 73 |     /* Read data to the memory */
 74 |     res = pf_read(buff, 16, &br);    /* Read data to the buff[] */
 75 |     if (res) die(res);               /* Check error */
 76 |     if (br != 16) die(255);          /* Check EOF */
 77 | 
 78 |     ....
 79 | 
 80 |     /* Forward data to the outgoing stream */
 81 |     do
 82 |         res = pf_read(0, 512, &br);  /* Send data to the stream */
 83 |     while (res || br != 512);        /* Break on error or eof */
 84 | 
 85 |     ....
 86 | 
 87 | }
 88 | 
89 |
90 | 91 |
92 |

QuickInfo

93 |

Always available.

94 |
95 | 96 |
97 |

References

98 |

pf_read, FATFS

99 |
100 | 101 |

Return

102 | 103 | 104 | -------------------------------------------------------------------------------- /pff/doc/pf/opendir.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - pf_opendir 10 | 11 | 12 | 13 | 14 |
15 |

pf_opendir

16 |

The pf_opendir function opens a directory.

17 |
18 | FRESULT pf_opendir (
19 |   DIR* dp,          /* [OUT] Pointer to the blank directory object structure */
20 |   const char* path  /* [IN]  Pointer to the directory name */
21 | );
22 | 
23 |
24 | 25 |
26 |

Parameters

27 |
28 |
dp
29 |
Pointer to the blank directory object to be created.
30 |
path
31 |
Pinter to the null-terminated string that specifies the directory name to be opened.
32 |
33 |
34 | 35 | 36 |
37 |

Return Values

38 |
39 |
FR_OK (0)
40 |
The function succeeded and the directory object is created. It is used for subsequent calls to read the directory entries.
41 |
FR_NO_FILE
42 |
Could not find the path.
43 |
FR_NOT_READY
44 |
The disk drive cannot work due to no medium in the drive or any other reason.
45 |
FR_DISK_ERR
46 |
The function failed due to a hard error in the disk function, a wrong FAT structure or an internal error.
47 |
FR_NOT_ENABLED
48 |
The volume has no work area.
49 |
50 |
51 | 52 | 53 |
54 |

Description

55 |

The pf_opendir() function opens an exsisting directory and creates the directory object for subsequent calls. The directory object structure can be discarded at any time without any procedure.

56 |
57 | 58 | 59 |
60 |

QuickInfo

61 |

Available when _USE_DIR == 1.

62 |
63 | 64 | 65 |
66 |

References

67 |

f_readdir, DIR

68 |
69 | 70 |

Return

71 | 72 | 73 | -------------------------------------------------------------------------------- /pff/doc/pf/read.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - pf_read 10 | 11 | 12 | 13 | 14 |
15 |

pf_read

16 |

The pf_read function reads data from the file.

17 |
18 | FRESULT pf_read (
19 |   void* buff,  /* [OUT] Pointer to the read buffer */
20 |   UINT btr,    /* [IN]  Number of bytes to read */
21 |   UINT* br     /* [OUT] Number of bytes read */
22 | );
23 | 
24 |
25 | 26 |
27 |

Parameters

28 |
29 |
buff
30 |
Pointer to the buffer to store the read data. A NULL specifies the destination is an outgoing stream.
31 |
btr
32 |
Number of bytes to read.
33 |
br
34 |
Pointer to the variable to return number of bytes read.
35 |
36 |
37 | 38 | 39 |
40 |

Return Values

41 |
42 |
FR_OK (0)
43 |
The function succeeded.
44 |
FR_DISK_ERR
45 |
The function failed due to a hard error in the disk function, a wrong FAT structure or an internal error.
46 |
FR_NOT_OPENED
47 |
The file has not been opened.
48 |
FR_NOT_ENABLED
49 |
The volume has not been mounted.
50 |
51 |
52 | 53 | 54 |
55 |

Description

56 |

The file read/write pointer in the file system object advances in number of bytes read. After the function succeeded, *br should be checked to detect end of file. In case of *br < btr, it means the read pointer reached end of file during read operation.

57 |

If a NULL is given to the buff, the read bytes will be forwarded to the outgoing stream instead of the memory. The streaming function will be typically built-in the disk_readp() function.

58 |
59 | 60 |
61 |

QuickInfo

62 |

Available when _USE_READ == 1.

63 |
64 | 65 | 66 |
67 |

References

68 |

pf_open, pf_write, FATFS

69 |
70 | 71 |

Return

72 | 73 | 74 | -------------------------------------------------------------------------------- /pff/doc/pf/readdir.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - pf_readdir 10 | 11 | 12 | 13 | 14 |
15 |

pf_readdir

16 |

The pf_readdir function reads directory entries.

17 |
 18 | FRESULT pf_readdir (
 19 |   DIR* dp,      /* [IN]  Pointer to the open directory object */
 20 |   FILINFO* fno  /* [OUT] Pointer to the file information structure */
 21 | );
 22 | 
23 |
24 | 25 |
26 |

Parameters

27 |
28 |
dp
29 |
Pointer to the open directory object.
30 |
fno
31 |
Pointer to the file information structure to store the read item.
32 |
33 |
34 | 35 | 36 |
37 |

Return Values

38 |
39 |
FR_OK (0)
40 |
The function succeeded.
41 |
FR_DISK_ERR
42 |
The function failed due to an error in the disk function, a wrong FAT structure or an internal error.
43 |
FR_NOT_OPENED
44 |
The directory object has not been opened.
45 |
46 |
47 | 48 | 49 |
50 |

Description

51 |

The pf_readdir() function reads directory entries in sequence. All items in the directory can be read by calling this function repeatedly. When all directory entries have been read and no item to read, the function returns a null string into member f_name[] in the file information structure without error. When a null pointer is given to the fno, the read index of the directory object will be rewinded.

52 |
53 | 54 | 55 |
56 |

Sample Code

57 |
 58 | FRESULT scan_files (char* path)
 59 | {
 60 |     FRESULT res;
 61 |     FILINFO fno;
 62 |     DIR dir;
 63 |     int i;
 64 | 
 65 | 
 66 |     res = pf_opendir(&dir, path);
 67 |     if (res == FR_OK) {
 68 |         i = strlen(path);
 69 |         for (;;) {
 70 |             res = pf_readdir(&dir, &fno);
 71 |             if (res != FR_OK || fno.fname[0] == 0) break;
 72 |             if (fno.fattrib & AM_DIR) {
 73 |                 sprintf(&path[i], "/%s", fno.fname);
 74 |                 res = scan_files(path);
 75 |                 if (res != FR_OK) break;
 76 |                 path[i] = 0;
 77 |             } else {
 78 |                 printf("%s/%s\n", path, fno.fname);
 79 |             }
 80 |         }
 81 |     }
 82 | 
 83 |     return res;
 84 | }
 85 | 
86 |
87 | 88 |
89 |

QuickInfo

90 |

Available when _USE_DIR == 1.

91 |
92 | 93 |
94 |

References

95 |

pf_opendir, FILINFO, DIR

96 |
97 | 98 |

Return

99 | 100 | 101 | -------------------------------------------------------------------------------- /pff/doc/pf/sdir.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - DIR 10 | 11 | 12 | 13 | 14 |
15 |

DIR

16 |

The DIR structure is used for the work area to read a directory by pf_oepndir, pf_readdir function.

17 |
18 | typedef struct {
19 |     WORD    index;     /* Current read/write index number */
20 |     BYTE*   fn;        /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
21 |     CLUST   sclust;    /* Table start cluster (0:Static table) */
22 |     CLUST   clust;     /* Current cluster */
23 |     DWORD   sect;      /* Current sector */
24 | } DIR;
25 | 
26 |
27 | 28 |

Return

29 | 30 | 31 | -------------------------------------------------------------------------------- /pff/doc/pf/sfatfs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - FATFS 10 | 11 | 12 | 13 | 14 |
15 |

FATFS

16 |

The FATFS structure holds dynamic work area of the logical drive and a file. It is given by application program and registerd/unregisterd to the Petit FatFs module with pf_mount function. There is no member that can be changed by application programs.

17 |
18 | typedef struct {
19 |     BYTE    fs_type;     /* FAT sub type */
20 |     BYTE    csize;       /* Number of sectors per cluster */
21 |     BYTE    flag;        /* File status flags */
22 |     BYTE    pad1;
23 |     WORD    n_rootdir;   /* Number of root directory entries (0 on FAT32) */
24 |     CLUST   n_fatent;    /* Number of FAT entries (= number of clusters + 2) */
25 |     DWORD   fatbase;     /* FAT start sector */
26 |     DWORD   dirbase;     /* Root directory start sector (Cluster# on FAT32) */
27 |     DWORD   database;    /* Data start sector */
28 |     DWORD   fptr;        /* File read/write pointer */
29 |     DWORD   fsize;       /* File size */
30 |     CLUST   org_clust;   /* File start cluster */
31 |     CLUST   curr_clust;  /* File current cluster */
32 |     DWORD   dsect;       /* File current data sector */
33 | } FATFS;
34 | 
35 |
36 | 37 |

Return

38 | 39 | 40 | -------------------------------------------------------------------------------- /pff/doc/pf/sfileinfo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - FILINFO 10 | 11 | 12 | 13 | 14 |
15 |

FILINFO

16 |

The FILINFO structure holds a file information returned by pf_readdir function.

17 |
18 | typedef struct {
19 |     DWORD   fsize;        /* File size */
20 |     WORD    fdate;        /* Last modified date */
21 |     WORD    ftime;        /* Last modified time */
22 |     BYTE    fattrib;      /* Attribute */
23 |     char    fname[13];    /* File name */
24 | } FILINFO;
25 | 
26 |
27 | 28 |

Members

29 |
30 |
fsize
31 |
Indicates size of the file in unit of byte. This is always zero when it is a directory.
32 |
fdate
33 |
Indicates the date that the file was modified or the directory was created.
34 |
35 |
bit15:9
36 |
Year origin from 1980 (0..127)
37 |
bit8:5
38 |
Month (1..12)
39 |
bit4:0
40 |
Day (1..31)
41 |
42 |
43 |
ftime
44 |
Indicates the time that the file was modified or the directory was created.
45 |
46 |
bit15:11
47 |
Hour (0..23)
48 |
bit10:5
49 |
Minute (0..59)
50 |
bit4:0
51 |
Second / 2 (0..29)
52 |
53 |
54 |
fattrib
55 |
Indicates the file/directory attribute in combination of AM_DIR, AM_RDO, AM_HID, AM_SYS and AM_ARC.
56 |
fname[]
57 |
Indicates the file/directory name in 8.3 format null-terminated string.
58 |
59 | 60 |

Return

61 | 62 | 63 | -------------------------------------------------------------------------------- /pff/doc/pf/write.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Petit FatFs - pf_write 10 | 11 | 12 | 13 | 14 |
15 |

pf_write

16 |

The pf_write function writes data to the file.

17 |
18 | FRESULT pf_write (
19 |   const void* buff, /* [IN]  Pointer to the data to be written */
20 |   UINT btw,         /* [IN]  Number of bytes to write */
21 |   UINT* bw          /* [OUT] Pointer to the variable to return number of bytes written */
22 | );
23 | 
24 |
25 | 26 |
27 |

Parameters

28 |
29 |
buff
30 |
Pointer to the data to be wtitten. A NULL specifies to finalize the current write operation.
31 |
btw
32 |
Number of bytes to write.
33 |
bw
34 |
Pointer to the variable to return number of bytes read.
35 |
36 |
37 | 38 | 39 |
40 |

Return Values

41 |
42 |
FR_OK (0)
43 |
The function succeeded.
44 |
FR_DISK_ERR
45 |
The function failed due to a hard error in the disk function, write protected, a wrong FAT structure or an internal error.
46 |
FR_NOT_OPENED
47 |
The file has not been opened.
48 |
FR_NOT_ENABLED
49 |
The volume has not been mounted.
50 |
51 |
52 | 53 | 54 |
55 |

Description

56 |

The write function has some restrictions listed below:

57 |
    58 |
  • Cannot create file. Only existing file can be written.
  • 59 |
  • Cannot expand file size.
  • 60 |
  • Cannot update time stamp of the file.
  • 61 |
  • Write operation can start/stop on the sector boundary.
  • 62 |
  • Read-only attribute of the file cannot block write operation.
  • 63 |
64 |

File write operation must be done in following sequence.

65 |
    66 |
  1. pf_lseek(ofs); read/write pointer must be moved to sector bundary prior to initiate write operation or it will be rounded-down to the sector boundary.
  2. 67 |
  3. pf_write(buff, btw, &bw); Initiate write operation. Write first data to the file.
  4. 68 |
  5. pf_write(buff, btw, &bw); Write next data. Any other file function cannot be used while a write operation is in progress.
  6. 69 |
  7. pf_write(0, 0, &bw); Finalize the write operation. If read/write pointer is not on the sector boundary, left bytes in the sector will be filled with zero.
  8. 70 |
71 |

The read/write pointer in the file system object advances in number of bytes written. After the function succeeded, *bw should be checked to detect end of file. In case of *bw < btw, it means the read/write pointer reached end of file during the write operation. Once a write operation is initiated, it must be finalized or the written data can be lost.

72 |
73 | 74 |
75 |

QuickInfo

76 |

Available when _USE_WRITE == 1.

77 |
78 | 79 |
80 |

References

81 |

pf_open, FATFS

82 |
83 | 84 |

Return

85 | 86 | 87 | -------------------------------------------------------------------------------- /pff/src/00readme.txt: -------------------------------------------------------------------------------- 1 | Petit FatFs Module Source Files R0.03 (C)ChaN, 2014 2 | 3 | 4 | FILES 5 | 6 | pff.h Common include file for Petit FatFs and application module. 7 | pff.c Petit FatFs module. 8 | diskio.h Common include file for Petit FatFs and disk I/O module. 9 | diskio.c Skeleton of low level disk I/O module. 10 | integer.h Alternative type definitions for integer variables. 11 | 12 | Low level disk I/O module is not included in this archive because the Petit 13 | FatFs module is only a generic file system layer and not depend on any 14 | specific storage device. You have to provide a low level disk I/O module that 15 | written to control your storage device. 16 | 17 | 18 | 19 | AGREEMENTS 20 | 21 | Petit FatFs module is an open source software to implement FAT file system to 22 | small embedded systems. This is a free software and is opened for education, 23 | research and commercial developments under license policy of following trems. 24 | 25 | Copyright (C) 2014, ChaN, all right reserved. 26 | 27 | * The Petit FatFs module is a free software and there is NO WARRANTY. 28 | * No restriction on use. You can use, modify and redistribute it for 29 | personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY. 30 | * Redistributions of source code must retain the above copyright notice. 31 | 32 | 33 | 34 | REVISION HISTORY 35 | 36 | Jun 15, 2009 R0.01a First release (Branched from FatFs R0.07b) 37 | 38 | Dec 14, 2009 R0.02 Added multiple code page support. 39 | Added write funciton. 40 | Changed stream read mode interface. 41 | Dec 07,'2010 R0.02a Added some configuration options. 42 | Fixed fails to open objects with DBCS character. 43 | 44 | Jun 10, 2014 R0.03 Separated out configuration options to pffconf.h. 45 | Added _USE_LCC option. 46 | Added _FS_FAT16 option. 47 | -------------------------------------------------------------------------------- /pff/src/diskio.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*/ 2 | /* Low level disk I/O module skeleton for Petit FatFs (C)ChaN, 2014 */ 3 | /*-----------------------------------------------------------------------*/ 4 | 5 | #include "diskio.h" 6 | 7 | 8 | /*-----------------------------------------------------------------------*/ 9 | /* Initialize Disk Drive */ 10 | /*-----------------------------------------------------------------------*/ 11 | 12 | DSTATUS disk_initialize (void) 13 | { 14 | DSTATUS stat; 15 | 16 | // Put your code here 17 | 18 | return stat; 19 | } 20 | 21 | 22 | 23 | /*-----------------------------------------------------------------------*/ 24 | /* Read Partial Sector */ 25 | /*-----------------------------------------------------------------------*/ 26 | 27 | DRESULT disk_readp ( 28 | BYTE* buff, /* Pointer to the destination object */ 29 | DWORD sector, /* Sector number (LBA) */ 30 | UINT offset, /* Offset in the sector */ 31 | UINT count /* Byte count (bit15:destination) */ 32 | ) 33 | { 34 | DRESULT res; 35 | 36 | // Put your code here 37 | 38 | return res; 39 | } 40 | 41 | 42 | 43 | /*-----------------------------------------------------------------------*/ 44 | /* Write Partial Sector */ 45 | /*-----------------------------------------------------------------------*/ 46 | 47 | DRESULT disk_writep ( 48 | BYTE* buff, /* Pointer to the data to be written, NULL:Initiate/Finalize write operation */ 49 | DWORD sc /* Sector number (LBA) or Number of bytes to send */ 50 | ) 51 | { 52 | DRESULT res; 53 | 54 | 55 | if (!buff) { 56 | if (sc) { 57 | 58 | // Initiate write process 59 | 60 | } else { 61 | 62 | // Finalize write process 63 | 64 | } 65 | } else { 66 | 67 | // Send data to the disk 68 | 69 | } 70 | 71 | return res; 72 | } 73 | 74 | -------------------------------------------------------------------------------- /pff/src/diskio.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------- 2 | / PFF - Low level disk interface modlue include file (C)ChaN, 2014 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include "integer.h" 13 | 14 | 15 | /* Status of Disk Functions */ 16 | typedef BYTE DSTATUS; 17 | 18 | 19 | /* Results of Disk Functions */ 20 | typedef enum { 21 | RES_OK = 0, /* 0: Function succeeded */ 22 | RES_ERROR, /* 1: Disk error */ 23 | RES_NOTRDY, /* 2: Not ready */ 24 | RES_PARERR /* 3: Invalid parameter */ 25 | } DRESULT; 26 | 27 | 28 | /*---------------------------------------*/ 29 | /* Prototypes for disk control functions */ 30 | 31 | DSTATUS disk_initialize (void); 32 | DRESULT disk_readp (BYTE* buff, DWORD sector, UINT offser, UINT count); 33 | DRESULT disk_writep (const BYTE* buff, DWORD sc); 34 | 35 | #define STA_NOINIT 0x01 /* Drive not initialized */ 36 | #define STA_NODISK 0x02 /* No medium in the drive */ 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif /* _DISKIO_DEFINED */ 43 | -------------------------------------------------------------------------------- /pff/src/integer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------*/ 2 | /* Integer type definitions for FatFs module */ 3 | /*-------------------------------------------*/ 4 | 5 | #ifndef _FF_INTEGER 6 | #define _FF_INTEGER 7 | 8 | #ifdef _WIN32 /* FatFs development platform */ 9 | 10 | #include 11 | #include 12 | 13 | #else /* Embedded platform */ 14 | 15 | /* This type MUST be 8 bit */ 16 | typedef unsigned char BYTE; 17 | 18 | /* These types MUST be 16 bit */ 19 | typedef short SHORT; 20 | typedef unsigned short WORD; 21 | typedef unsigned short WCHAR; 22 | 23 | /* These types MUST be 16 bit or 32 bit */ 24 | typedef int INT; 25 | typedef unsigned int UINT; 26 | 27 | /* These types MUST be 32 bit */ 28 | typedef long LONG; 29 | typedef unsigned long DWORD; 30 | 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /pff/src/pff.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / Petit FatFs - FAT file system module R0.03 (C)ChaN, 2014 3 | /-----------------------------------------------------------------------------/ 4 | / Petit FatFs module is a generic FAT file system module for small embedded 5 | / systems. This is a free software that opened for education, research and 6 | / commercial developments under license policy of following trems. 7 | / 8 | / Copyright (C) 2014, ChaN, all right reserved. 9 | / 10 | / * The Petit FatFs module is a free software and there is NO WARRANTY. 11 | / * No restriction on use. You can use, modify and redistribute it for 12 | / personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. 13 | / * Redistributions of source code must retain the above copyright notice. 14 | / 15 | /-----------------------------------------------------------------------------/ 16 | / Jun 15,'09 R0.01a First release. 17 | / 18 | / Dec 14,'09 R0.02 Added multiple code page support. 19 | / Added write funciton. 20 | / Changed stream read mode interface. 21 | / Dec 07,'10 R0.02a Added some configuration options. 22 | / Fixed fails to open objects with DBCS character. 23 | 24 | / Jun 10,'14 R0.03 Separated out configuration options to pffconf.h. 25 | / Added _USE_LCC option. 26 | / Added _FS_FAT16 option. 27 | /----------------------------------------------------------------------------*/ 28 | 29 | #include "pff.h" /* Petit FatFs configurations and declarations */ 30 | #include "diskio.h" /* Declarations of low level disk I/O functions */ 31 | 32 | 33 | 34 | /*-------------------------------------------------------------------------- 35 | 36 | Module Private Definitions 37 | 38 | ---------------------------------------------------------------------------*/ 39 | 40 | 41 | #if _PFATFS != 4004 /* Revision ID */ 42 | #error Wrong include file (pff.h). 43 | #endif 44 | 45 | #if _FS_FAT32 46 | #if !_FS_FAT16 && !_FS_FAT12 47 | #define _FS_32ONLY 1 48 | #else 49 | #define _FS_32ONLY 0 50 | #endif 51 | #else 52 | #if !_FS_FAT16 && !_FS_FAT12 53 | #error Wrong _FS_FATxx setting. 54 | #endif 55 | #define _FS_32ONLY 0 56 | #endif 57 | 58 | #define ABORT(err) {fs->flag = 0; return err;} 59 | 60 | 61 | 62 | /*--------------------------------------------------------*/ 63 | /* DBCS code ranges and SBCS extend char conversion table */ 64 | /*--------------------------------------------------------*/ 65 | 66 | #if _CODE_PAGE == 932 /* Japanese Shift-JIS */ 67 | #define _DF1S 0x81 /* DBC 1st byte range 1 start */ 68 | #define _DF1E 0x9F /* DBC 1st byte range 1 end */ 69 | #define _DF2S 0xE0 /* DBC 1st byte range 2 start */ 70 | #define _DF2E 0xFC /* DBC 1st byte range 2 end */ 71 | #define _DS1S 0x40 /* DBC 2nd byte range 1 start */ 72 | #define _DS1E 0x7E /* DBC 2nd byte range 1 end */ 73 | #define _DS2S 0x80 /* DBC 2nd byte range 2 start */ 74 | #define _DS2E 0xFC /* DBC 2nd byte range 2 end */ 75 | 76 | #elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ 77 | #define _DF1S 0x81 78 | #define _DF1E 0xFE 79 | #define _DS1S 0x40 80 | #define _DS1E 0x7E 81 | #define _DS2S 0x80 82 | #define _DS2E 0xFE 83 | 84 | #elif _CODE_PAGE == 949 /* Korean */ 85 | #define _DF1S 0x81 86 | #define _DF1E 0xFE 87 | #define _DS1S 0x41 88 | #define _DS1E 0x5A 89 | #define _DS2S 0x61 90 | #define _DS2E 0x7A 91 | #define _DS3S 0x81 92 | #define _DS3E 0xFE 93 | 94 | #elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ 95 | #define _DF1S 0x81 96 | #define _DF1E 0xFE 97 | #define _DS1S 0x40 98 | #define _DS1E 0x7E 99 | #define _DS2S 0xA1 100 | #define _DS2E 0xFE 101 | 102 | #elif _CODE_PAGE == 437 /* U.S. (OEM) */ 103 | #define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 104 | 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 105 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 106 | 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 107 | 108 | #elif _CODE_PAGE == 720 /* Arabic (OEM) */ 109 | #define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 110 | 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 111 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 112 | 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 113 | 114 | #elif _CODE_PAGE == 737 /* Greek (OEM) */ 115 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ 116 | 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 117 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 118 | 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 119 | 120 | #elif _CODE_PAGE == 775 /* Baltic (OEM) */ 121 | #define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 122 | 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 123 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 124 | 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 125 | 126 | #elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */ 127 | #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 128 | 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 129 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 130 | 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 131 | 132 | #elif _CODE_PAGE == 852 /* Latin 2 (OEM) */ 133 | #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \ 134 | 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ 135 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 136 | 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} 137 | 138 | #elif _CODE_PAGE == 855 /* Cyrillic (OEM) */ 139 | #define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ 140 | 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ 141 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ 142 | 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} 143 | 144 | #elif _CODE_PAGE == 857 /* Turkish (OEM) */ 145 | #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ 146 | 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 147 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 148 | 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 149 | 150 | #elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */ 151 | #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 152 | 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 153 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 154 | 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 155 | 156 | #elif _CODE_PAGE == 862 /* Hebrew (OEM) */ 157 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 158 | 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 159 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 160 | 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 161 | 162 | #elif _CODE_PAGE == 866 /* Russian (OEM) */ 163 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 164 | 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 165 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 166 | 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 167 | 168 | #elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */ 169 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 170 | 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 171 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 172 | 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 173 | 174 | #elif _CODE_PAGE == 1250 /* Central Europe (Windows) */ 175 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ 176 | 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \ 177 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 178 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} 179 | 180 | #elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */ 181 | #define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ 182 | 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \ 183 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 184 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF} 185 | 186 | #elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */ 187 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \ 188 | 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 189 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 190 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} 191 | 192 | #elif _CODE_PAGE == 1253 /* Greek (Windows) */ 193 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 194 | 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 195 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \ 196 | 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF} 197 | 198 | #elif _CODE_PAGE == 1254 /* Turkish (Windows) */ 199 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \ 200 | 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 201 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 202 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} 203 | 204 | #elif _CODE_PAGE == 1255 /* Hebrew (Windows) */ 205 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 206 | 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 207 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 208 | 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 209 | 210 | #elif _CODE_PAGE == 1256 /* Arabic (Windows) */ 211 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \ 212 | 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 213 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 214 | 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF} 215 | 216 | #elif _CODE_PAGE == 1257 /* Baltic (Windows) */ 217 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 218 | 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \ 219 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 220 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} 221 | 222 | #elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */ 223 | #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \ 224 | 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 225 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 226 | 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F} 227 | 228 | #else 229 | #error Unknown code page. 230 | 231 | #endif 232 | 233 | 234 | 235 | /* Character code support macros */ 236 | 237 | #define IsUpper(c) (((c)>='A')&&((c)<='Z')) 238 | #define IsLower(c) (((c)>='a')&&((c)<='z')) 239 | 240 | #ifndef _EXCVT /* DBCS configuration */ 241 | 242 | #ifdef _DF2S /* Two 1st byte areas */ 243 | #define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) 244 | #else /* One 1st byte area */ 245 | #define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) 246 | #endif 247 | 248 | #ifdef _DS3S /* Three 2nd byte areas */ 249 | #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) 250 | #else /* Two 2nd byte areas */ 251 | #define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) 252 | #endif 253 | 254 | #else /* SBCS configuration */ 255 | 256 | #define IsDBCS1(c) 0 257 | #define IsDBCS2(c) 0 258 | 259 | #endif /* _EXCVT */ 260 | 261 | 262 | /* FatFs refers the members in the FAT structures with byte offset instead 263 | / of structure member because there are incompatibility of the packing option 264 | / between various compilers. */ 265 | 266 | #define BS_jmpBoot 0 267 | #define BS_OEMName 3 268 | #define BPB_BytsPerSec 11 269 | #define BPB_SecPerClus 13 270 | #define BPB_RsvdSecCnt 14 271 | #define BPB_NumFATs 16 272 | #define BPB_RootEntCnt 17 273 | #define BPB_TotSec16 19 274 | #define BPB_Media 21 275 | #define BPB_FATSz16 22 276 | #define BPB_SecPerTrk 24 277 | #define BPB_NumHeads 26 278 | #define BPB_HiddSec 28 279 | #define BPB_TotSec32 32 280 | #define BS_55AA 510 281 | 282 | #define BS_DrvNum 36 283 | #define BS_BootSig 38 284 | #define BS_VolID 39 285 | #define BS_VolLab 43 286 | #define BS_FilSysType 54 287 | 288 | #define BPB_FATSz32 36 289 | #define BPB_ExtFlags 40 290 | #define BPB_FSVer 42 291 | #define BPB_RootClus 44 292 | #define BPB_FSInfo 48 293 | #define BPB_BkBootSec 50 294 | #define BS_DrvNum32 64 295 | #define BS_BootSig32 66 296 | #define BS_VolID32 67 297 | #define BS_VolLab32 71 298 | #define BS_FilSysType32 82 299 | 300 | #define MBR_Table 446 301 | 302 | #define DIR_Name 0 303 | #define DIR_Attr 11 304 | #define DIR_NTres 12 305 | #define DIR_CrtTime 14 306 | #define DIR_CrtDate 16 307 | #define DIR_FstClusHI 20 308 | #define DIR_WrtTime 22 309 | #define DIR_WrtDate 24 310 | #define DIR_FstClusLO 26 311 | #define DIR_FileSize 28 312 | 313 | 314 | 315 | /*-------------------------------------------------------------------------- 316 | 317 | Private Functions 318 | 319 | ---------------------------------------------------------------------------*/ 320 | 321 | 322 | static 323 | FATFS *FatFs; /* Pointer to the file system object (logical drive) */ 324 | 325 | 326 | /* Fill memory */ 327 | static 328 | void mem_set (void* dst, int val, int cnt) { 329 | char *d = (char*)dst; 330 | while (cnt--) *d++ = (char)val; 331 | } 332 | 333 | /* Compare memory to memory */ 334 | static 335 | int mem_cmp (const void* dst, const void* src, int cnt) { 336 | const char *d = (const char *)dst, *s = (const char *)src; 337 | int r = 0; 338 | while (cnt-- && (r = *d++ - *s++) == 0) ; 339 | return r; 340 | } 341 | 342 | 343 | 344 | /*-----------------------------------------------------------------------*/ 345 | /* FAT access - Read value of a FAT entry */ 346 | /*-----------------------------------------------------------------------*/ 347 | 348 | static 349 | CLUST get_fat ( /* 1:IO error, Else:Cluster status */ 350 | CLUST clst /* Cluster# to get the link information */ 351 | ) 352 | { 353 | BYTE buf[4]; 354 | FATFS *fs = FatFs; 355 | 356 | if (clst < 2 || clst >= fs->n_fatent) /* Range check */ 357 | return 1; 358 | 359 | switch (fs->fs_type) { 360 | #if _FS_FAT12 361 | case FS_FAT12 : { 362 | UINT wc, bc, ofs; 363 | 364 | bc = (UINT)clst; bc += bc / 2; 365 | ofs = bc % 512; bc /= 512; 366 | if (ofs != 511) { 367 | if (disk_readp(buf, fs->fatbase + bc, ofs, 2)) break; 368 | } else { 369 | if (disk_readp(buf, fs->fatbase + bc, 511, 1)) break; 370 | if (disk_readp(buf+1, fs->fatbase + bc + 1, 0, 1)) break; 371 | } 372 | wc = LD_WORD(buf); 373 | return (clst & 1) ? (wc >> 4) : (wc & 0xFFF); 374 | } 375 | #endif 376 | #if _FS_FAT16 377 | case FS_FAT16 : 378 | if (disk_readp(buf, fs->fatbase + clst / 256, ((UINT)clst % 256) * 2, 2)) break; 379 | return LD_WORD(buf); 380 | #endif 381 | #if _FS_FAT32 382 | case FS_FAT32 : 383 | if (disk_readp(buf, fs->fatbase + clst / 128, ((UINT)clst % 128) * 4, 4)) break; 384 | return LD_DWORD(buf) & 0x0FFFFFFF; 385 | #endif 386 | } 387 | 388 | return 1; /* An error occured at the disk I/O layer */ 389 | } 390 | 391 | 392 | 393 | 394 | /*-----------------------------------------------------------------------*/ 395 | /* Get sector# from cluster# / Get cluster field from directory entry */ 396 | /*-----------------------------------------------------------------------*/ 397 | 398 | static 399 | DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ 400 | CLUST clst /* Cluster# to be converted */ 401 | ) 402 | { 403 | FATFS *fs = FatFs; 404 | 405 | 406 | clst -= 2; 407 | if (clst >= (fs->n_fatent - 2)) return 0; /* Invalid cluster# */ 408 | return (DWORD)clst * fs->csize + fs->database; 409 | } 410 | 411 | 412 | static 413 | CLUST get_clust ( 414 | BYTE* dir /* Pointer to directory entry */ 415 | ) 416 | { 417 | FATFS *fs = FatFs; 418 | CLUST clst = 0; 419 | 420 | 421 | if (_FS_32ONLY || (_FS_FAT32 && fs->fs_type == FS_FAT32)) { 422 | clst = LD_WORD(dir+DIR_FstClusHI); 423 | clst <<= 16; 424 | } 425 | clst |= LD_WORD(dir+DIR_FstClusLO); 426 | 427 | return clst; 428 | } 429 | 430 | 431 | /*-----------------------------------------------------------------------*/ 432 | /* Directory handling - Rewind directory index */ 433 | /*-----------------------------------------------------------------------*/ 434 | 435 | static 436 | FRESULT dir_rewind ( 437 | DIR *dj /* Pointer to directory object */ 438 | ) 439 | { 440 | CLUST clst; 441 | FATFS *fs = FatFs; 442 | 443 | 444 | dj->index = 0; 445 | clst = dj->sclust; 446 | if (clst == 1 || clst >= fs->n_fatent) /* Check start cluster range */ 447 | return FR_DISK_ERR; 448 | if (_FS_FAT32 && !clst && (_FS_32ONLY || fs->fs_type == FS_FAT32)) /* Replace cluster# 0 with root cluster# if in FAT32 */ 449 | clst = (CLUST)fs->dirbase; 450 | dj->clust = clst; /* Current cluster */ 451 | dj->sect = (_FS_32ONLY || clst) ? clust2sect(clst) : fs->dirbase; /* Current sector */ 452 | 453 | return FR_OK; /* Seek succeeded */ 454 | } 455 | 456 | 457 | 458 | 459 | /*-----------------------------------------------------------------------*/ 460 | /* Directory handling - Move directory index next */ 461 | /*-----------------------------------------------------------------------*/ 462 | 463 | static 464 | FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table */ 465 | DIR *dj /* Pointer to directory object */ 466 | ) 467 | { 468 | CLUST clst; 469 | WORD i; 470 | FATFS *fs = FatFs; 471 | 472 | 473 | i = dj->index + 1; 474 | if (!i || !dj->sect) /* Report EOT when index has reached 65535 */ 475 | return FR_NO_FILE; 476 | 477 | if (!(i % 16)) { /* Sector changed? */ 478 | dj->sect++; /* Next sector */ 479 | 480 | if (dj->clust == 0) { /* Static table */ 481 | if (i >= fs->n_rootdir) /* Report EOT when end of table */ 482 | return FR_NO_FILE; 483 | } 484 | else { /* Dynamic table */ 485 | if (((i / 16) & (fs->csize - 1)) == 0) { /* Cluster changed? */ 486 | clst = get_fat(dj->clust); /* Get next cluster */ 487 | if (clst <= 1) return FR_DISK_ERR; 488 | if (clst >= fs->n_fatent) /* When it reached end of dynamic table */ 489 | return FR_NO_FILE; /* Report EOT */ 490 | dj->clust = clst; /* Initialize data for new cluster */ 491 | dj->sect = clust2sect(clst); 492 | } 493 | } 494 | } 495 | 496 | dj->index = i; 497 | 498 | return FR_OK; 499 | } 500 | 501 | 502 | 503 | 504 | /*-----------------------------------------------------------------------*/ 505 | /* Directory handling - Find an object in the directory */ 506 | /*-----------------------------------------------------------------------*/ 507 | 508 | static 509 | FRESULT dir_find ( 510 | DIR *dj, /* Pointer to the directory object linked to the file name */ 511 | BYTE *dir /* 32-byte working buffer */ 512 | ) 513 | { 514 | FRESULT res; 515 | BYTE c; 516 | 517 | 518 | res = dir_rewind(dj); /* Rewind directory object */ 519 | if (res != FR_OK) return res; 520 | 521 | do { 522 | res = disk_readp(dir, dj->sect, (dj->index % 16) * 32, 32) /* Read an entry */ 523 | ? FR_DISK_ERR : FR_OK; 524 | if (res != FR_OK) break; 525 | c = dir[DIR_Name]; /* First character */ 526 | if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ 527 | if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */ 528 | break; 529 | res = dir_next(dj); /* Next entry */ 530 | } while (res == FR_OK); 531 | 532 | return res; 533 | } 534 | 535 | 536 | 537 | 538 | /*-----------------------------------------------------------------------*/ 539 | /* Read an object from the directory */ 540 | /*-----------------------------------------------------------------------*/ 541 | #if _USE_DIR 542 | static 543 | FRESULT dir_read ( 544 | DIR *dj, /* Pointer to the directory object to store read object name */ 545 | BYTE *dir /* 32-byte working buffer */ 546 | ) 547 | { 548 | FRESULT res; 549 | BYTE a, c; 550 | 551 | 552 | res = FR_NO_FILE; 553 | while (dj->sect) { 554 | res = disk_readp(dir, dj->sect, (dj->index % 16) * 32, 32) /* Read an entry */ 555 | ? FR_DISK_ERR : FR_OK; 556 | if (res != FR_OK) break; 557 | c = dir[DIR_Name]; 558 | if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ 559 | a = dir[DIR_Attr] & AM_MASK; 560 | if (c != 0xE5 && c != '.' && !(a & AM_VOL)) /* Is it a valid entry? */ 561 | break; 562 | res = dir_next(dj); /* Next entry */ 563 | if (res != FR_OK) break; 564 | } 565 | 566 | if (res != FR_OK) dj->sect = 0; 567 | 568 | return res; 569 | } 570 | #endif 571 | 572 | 573 | 574 | /*-----------------------------------------------------------------------*/ 575 | /* Pick a segment and create the object name in directory form */ 576 | /*-----------------------------------------------------------------------*/ 577 | 578 | 579 | static 580 | FRESULT create_name ( 581 | DIR *dj, /* Pointer to the directory object */ 582 | const char **path /* Pointer to pointer to the segment in the path string */ 583 | ) 584 | { 585 | BYTE c, ni, si, i, *sfn; 586 | const char *p; 587 | #if _USE_LCC 588 | #ifdef _EXCVT 589 | static const BYTE cvt[] = _EXCVT; 590 | #endif 591 | #endif 592 | 593 | /* Create file name in directory form */ 594 | sfn = dj->fn; 595 | mem_set(sfn, ' ', 11); 596 | si = i = 0; ni = 8; 597 | p = *path; 598 | for (;;) { 599 | c = p[si++]; 600 | if (c <= ' ' || c == '/') break; /* Break on end of segment */ 601 | if (c == '.' || i >= ni) { 602 | if (ni != 8 || c != '.') break; 603 | i = 8; ni = 11; 604 | continue; 605 | } 606 | #if _USE_LCC 607 | #ifdef _EXCVT 608 | if (c >= 0x80) /* To upper extended char (SBCS) */ 609 | c = cvt[c - 0x80]; 610 | #endif 611 | if (IsDBCS1(c) && i < ni - 1) { /* DBC 1st byte? */ 612 | BYTE d = p[si++]; /* Get 2nd byte */ 613 | sfn[i++] = c; 614 | sfn[i++] = d; 615 | } else 616 | #endif 617 | { /* Single byte code */ 618 | if (_USE_LCC && IsLower(c)) c -= 0x20; /* toupper */ 619 | sfn[i++] = c; 620 | } 621 | } 622 | *path = &p[si]; /* Rerurn pointer to the next segment */ 623 | 624 | sfn[11] = (c <= ' ') ? 1 : 0; /* Set last segment flag if end of path */ 625 | 626 | return FR_OK; 627 | } 628 | 629 | 630 | 631 | 632 | /*-----------------------------------------------------------------------*/ 633 | /* Get file information from directory entry */ 634 | /*-----------------------------------------------------------------------*/ 635 | #if _USE_DIR 636 | static 637 | void get_fileinfo ( /* No return code */ 638 | DIR *dj, /* Pointer to the directory object */ 639 | BYTE *dir, /* 32-byte working buffer */ 640 | FILINFO *fno /* Pointer to store the file information */ 641 | ) 642 | { 643 | BYTE i, c; 644 | char *p; 645 | 646 | 647 | p = fno->fname; 648 | if (dj->sect) { 649 | for (i = 0; i < 8; i++) { /* Copy file name body */ 650 | c = dir[i]; 651 | if (c == ' ') break; 652 | if (c == 0x05) c = 0xE5; 653 | *p++ = c; 654 | } 655 | if (dir[8] != ' ') { /* Copy file name extension */ 656 | *p++ = '.'; 657 | for (i = 8; i < 11; i++) { 658 | c = dir[i]; 659 | if (c == ' ') break; 660 | *p++ = c; 661 | } 662 | } 663 | fno->fattrib = dir[DIR_Attr]; /* Attribute */ 664 | fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */ 665 | fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */ 666 | fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */ 667 | } 668 | *p = 0; 669 | } 670 | #endif /* _USE_DIR */ 671 | 672 | 673 | 674 | /*-----------------------------------------------------------------------*/ 675 | /* Follow a file path */ 676 | /*-----------------------------------------------------------------------*/ 677 | 678 | static 679 | FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ 680 | DIR *dj, /* Directory object to return last directory and found object */ 681 | BYTE *dir, /* 32-byte working buffer */ 682 | const char *path /* Full-path string to find a file or directory */ 683 | ) 684 | { 685 | FRESULT res; 686 | 687 | 688 | while (*path == ' ') path++; /* Strip leading spaces */ 689 | if (*path == '/') path++; /* Strip heading separator if exist */ 690 | dj->sclust = 0; /* Set start directory (always root dir) */ 691 | 692 | if ((BYTE)*path < ' ') { /* Null path means the root directory */ 693 | res = dir_rewind(dj); 694 | dir[0] = 0; 695 | 696 | } else { /* Follow path */ 697 | for (;;) { 698 | res = create_name(dj, &path); /* Get a segment */ 699 | if (res != FR_OK) break; 700 | res = dir_find(dj, dir); /* Find it */ 701 | if (res != FR_OK) break; /* Could not find the object */ 702 | if (dj->fn[11]) break; /* Last segment match. Function completed. */ 703 | if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow path because it is a file */ 704 | res = FR_NO_FILE; break; 705 | } 706 | dj->sclust = get_clust(dir); /* Follow next */ 707 | } 708 | } 709 | 710 | return res; 711 | } 712 | 713 | 714 | 715 | 716 | /*-----------------------------------------------------------------------*/ 717 | /* Check a sector if it is an FAT boot record */ 718 | /*-----------------------------------------------------------------------*/ 719 | 720 | static 721 | BYTE check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */ 722 | BYTE *buf, /* Working buffer */ 723 | DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ 724 | ) 725 | { 726 | if (disk_readp(buf, sect, 510, 2)) /* Read the boot record */ 727 | return 3; 728 | if (LD_WORD(buf) != 0xAA55) /* Check record signature */ 729 | return 2; 730 | 731 | if (!_FS_32ONLY && !disk_readp(buf, sect, BS_FilSysType, 2) && LD_WORD(buf) == 0x4146) /* Check FAT12/16 */ 732 | return 0; 733 | if (_FS_FAT32 && !disk_readp(buf, sect, BS_FilSysType32, 2) && LD_WORD(buf) == 0x4146) /* Check FAT32 */ 734 | return 0; 735 | return 1; 736 | } 737 | 738 | 739 | 740 | 741 | /*-------------------------------------------------------------------------- 742 | 743 | Public Functions 744 | 745 | --------------------------------------------------------------------------*/ 746 | 747 | 748 | 749 | /*-----------------------------------------------------------------------*/ 750 | /* Mount/Unmount a Locical Drive */ 751 | /*-----------------------------------------------------------------------*/ 752 | 753 | FRESULT pf_mount ( 754 | FATFS *fs /* Pointer to new file system object */ 755 | ) 756 | { 757 | BYTE fmt, buf[36]; 758 | DWORD bsect, fsize, tsect, mclst; 759 | 760 | 761 | FatFs = 0; 762 | 763 | if (disk_initialize() & STA_NOINIT) /* Check if the drive is ready or not */ 764 | return FR_NOT_READY; 765 | 766 | /* Search FAT partition on the drive */ 767 | bsect = 0; 768 | fmt = check_fs(buf, bsect); /* Check sector 0 as an SFD format */ 769 | if (fmt == 1) { /* Not an FAT boot record, it may be FDISK format */ 770 | /* Check a partition listed in top of the partition table */ 771 | if (disk_readp(buf, bsect, MBR_Table, 16)) { /* 1st partition entry */ 772 | fmt = 3; 773 | } else { 774 | if (buf[4]) { /* Is the partition existing? */ 775 | bsect = LD_DWORD(&buf[8]); /* Partition offset in LBA */ 776 | fmt = check_fs(buf, bsect); /* Check the partition */ 777 | } 778 | } 779 | } 780 | if (fmt == 3) return FR_DISK_ERR; 781 | if (fmt) return FR_NO_FILESYSTEM; /* No valid FAT patition is found */ 782 | 783 | /* Initialize the file system object */ 784 | if (disk_readp(buf, bsect, 13, sizeof (buf))) return FR_DISK_ERR; 785 | 786 | fsize = LD_WORD(buf+BPB_FATSz16-13); /* Number of sectors per FAT */ 787 | if (!fsize) fsize = LD_DWORD(buf+BPB_FATSz32-13); 788 | 789 | fsize *= buf[BPB_NumFATs-13]; /* Number of sectors in FAT area */ 790 | fs->fatbase = bsect + LD_WORD(buf+BPB_RsvdSecCnt-13); /* FAT start sector (lba) */ 791 | fs->csize = buf[BPB_SecPerClus-13]; /* Number of sectors per cluster */ 792 | fs->n_rootdir = LD_WORD(buf+BPB_RootEntCnt-13); /* Nmuber of root directory entries */ 793 | tsect = LD_WORD(buf+BPB_TotSec16-13); /* Number of sectors on the file system */ 794 | if (!tsect) tsect = LD_DWORD(buf+BPB_TotSec32-13); 795 | mclst = (tsect /* Last cluster# + 1 */ 796 | - LD_WORD(buf+BPB_RsvdSecCnt-13) - fsize - fs->n_rootdir / 16 797 | ) / fs->csize + 2; 798 | fs->n_fatent = (CLUST)mclst; 799 | 800 | fmt = 0; /* Determine the FAT sub type */ 801 | if (_FS_FAT12 && mclst < 0xFF7) 802 | fmt = FS_FAT12; 803 | if (_FS_FAT16 && mclst >= 0xFF8 && mclst < 0xFFF7) 804 | fmt = FS_FAT16; 805 | if (_FS_FAT32 && mclst >= 0xFFF7) 806 | fmt = FS_FAT32; 807 | if (!fmt) return FR_NO_FILESYSTEM; 808 | fs->fs_type = fmt; 809 | 810 | if (_FS_32ONLY || (_FS_FAT32 && fmt == FS_FAT32)) 811 | fs->dirbase = LD_DWORD(buf+(BPB_RootClus-13)); /* Root directory start cluster */ 812 | else 813 | fs->dirbase = fs->fatbase + fsize; /* Root directory start sector (lba) */ 814 | fs->database = fs->fatbase + fsize + fs->n_rootdir / 16; /* Data start sector (lba) */ 815 | 816 | fs->flag = 0; 817 | FatFs = fs; 818 | 819 | return FR_OK; 820 | } 821 | 822 | 823 | 824 | 825 | /*-----------------------------------------------------------------------*/ 826 | /* Open or Create a File */ 827 | /*-----------------------------------------------------------------------*/ 828 | 829 | FRESULT pf_open ( 830 | const char *path /* Pointer to the file name */ 831 | ) 832 | { 833 | FRESULT res; 834 | DIR dj; 835 | BYTE sp[12], dir[32]; 836 | FATFS *fs = FatFs; 837 | 838 | 839 | if (!fs) return FR_NOT_ENABLED; /* Check file system */ 840 | 841 | fs->flag = 0; 842 | dj.fn = sp; 843 | res = follow_path(&dj, dir, path); /* Follow the file path */ 844 | if (res != FR_OK) return res; /* Follow failed */ 845 | if (!dir[0] || (dir[DIR_Attr] & AM_DIR)) /* It is a directory */ 846 | return FR_NO_FILE; 847 | 848 | fs->org_clust = get_clust(dir); /* File start cluster */ 849 | fs->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */ 850 | fs->fptr = 0; /* File pointer */ 851 | fs->flag = FA_OPENED; 852 | 853 | return FR_OK; 854 | } 855 | 856 | 857 | 858 | 859 | /*-----------------------------------------------------------------------*/ 860 | /* Read File */ 861 | /*-----------------------------------------------------------------------*/ 862 | #if _USE_READ 863 | 864 | FRESULT pf_read ( 865 | void* buff, /* Pointer to the read buffer (NULL:Forward data to the stream)*/ 866 | UINT btr, /* Number of bytes to read */ 867 | UINT* br /* Pointer to number of bytes read */ 868 | ) 869 | { 870 | DRESULT dr; 871 | CLUST clst; 872 | DWORD sect, remain; 873 | UINT rcnt; 874 | BYTE cs, *rbuff = buff; 875 | FATFS *fs = FatFs; 876 | 877 | 878 | *br = 0; 879 | if (!fs) return FR_NOT_ENABLED; /* Check file system */ 880 | if (!(fs->flag & FA_OPENED)) /* Check if opened */ 881 | return FR_NOT_OPENED; 882 | 883 | remain = fs->fsize - fs->fptr; 884 | if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ 885 | 886 | while (btr) { /* Repeat until all data transferred */ 887 | if ((fs->fptr % 512) == 0) { /* On the sector boundary? */ 888 | cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1)); /* Sector offset in the cluster */ 889 | if (!cs) { /* On the cluster boundary? */ 890 | if (fs->fptr == 0) /* On the top of the file? */ 891 | clst = fs->org_clust; 892 | else 893 | clst = get_fat(fs->curr_clust); 894 | if (clst <= 1) ABORT(FR_DISK_ERR); 895 | fs->curr_clust = clst; /* Update current cluster */ 896 | } 897 | sect = clust2sect(fs->curr_clust); /* Get current sector */ 898 | if (!sect) ABORT(FR_DISK_ERR); 899 | fs->dsect = sect + cs; 900 | } 901 | rcnt = 512 - (UINT)fs->fptr % 512; /* Get partial sector data from sector buffer */ 902 | if (rcnt > btr) rcnt = btr; 903 | dr = disk_readp(!buff ? 0 : rbuff, fs->dsect, (UINT)fs->fptr % 512, rcnt); 904 | if (dr) ABORT(FR_DISK_ERR); 905 | fs->fptr += rcnt; rbuff += rcnt; /* Update pointers and counters */ 906 | btr -= rcnt; *br += rcnt; 907 | } 908 | 909 | return FR_OK; 910 | } 911 | #endif 912 | 913 | 914 | 915 | /*-----------------------------------------------------------------------*/ 916 | /* Write File */ 917 | /*-----------------------------------------------------------------------*/ 918 | #if _USE_WRITE 919 | 920 | FRESULT pf_write ( 921 | const void* buff, /* Pointer to the data to be written */ 922 | UINT btw, /* Number of bytes to write (0:Finalize the current write operation) */ 923 | UINT* bw /* Pointer to number of bytes written */ 924 | ) 925 | { 926 | CLUST clst; 927 | DWORD sect, remain; 928 | const BYTE *p = buff; 929 | BYTE cs; 930 | UINT wcnt; 931 | FATFS *fs = FatFs; 932 | 933 | 934 | *bw = 0; 935 | if (!fs) return FR_NOT_ENABLED; /* Check file system */ 936 | if (!(fs->flag & FA_OPENED)) /* Check if opened */ 937 | return FR_NOT_OPENED; 938 | 939 | if (!btw) { /* Finalize request */ 940 | if ((fs->flag & FA__WIP) && disk_writep(0, 0)) ABORT(FR_DISK_ERR); 941 | fs->flag &= ~FA__WIP; 942 | return FR_OK; 943 | } else { /* Write data request */ 944 | if (!(fs->flag & FA__WIP)) /* Round-down fptr to the sector boundary */ 945 | fs->fptr &= 0xFFFFFE00; 946 | } 947 | remain = fs->fsize - fs->fptr; 948 | if (btw > remain) btw = (UINT)remain; /* Truncate btw by remaining bytes */ 949 | 950 | while (btw) { /* Repeat until all data transferred */ 951 | if ((UINT)fs->fptr % 512 == 0) { /* On the sector boundary? */ 952 | cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1)); /* Sector offset in the cluster */ 953 | if (!cs) { /* On the cluster boundary? */ 954 | if (fs->fptr == 0) /* On the top of the file? */ 955 | clst = fs->org_clust; 956 | else 957 | clst = get_fat(fs->curr_clust); 958 | if (clst <= 1) ABORT(FR_DISK_ERR); 959 | fs->curr_clust = clst; /* Update current cluster */ 960 | } 961 | sect = clust2sect(fs->curr_clust); /* Get current sector */ 962 | if (!sect) ABORT(FR_DISK_ERR); 963 | fs->dsect = sect + cs; 964 | if (disk_writep(0, fs->dsect)) ABORT(FR_DISK_ERR); /* Initiate a sector write operation */ 965 | fs->flag |= FA__WIP; 966 | } 967 | wcnt = 512 - (UINT)fs->fptr % 512; /* Number of bytes to write to the sector */ 968 | if (wcnt > btw) wcnt = btw; 969 | if (disk_writep(p, wcnt)) ABORT(FR_DISK_ERR); /* Send data to the sector */ 970 | fs->fptr += wcnt; p += wcnt; /* Update pointers and counters */ 971 | btw -= wcnt; *bw += wcnt; 972 | if ((UINT)fs->fptr % 512 == 0) { 973 | if (disk_writep(0, 0)) ABORT(FR_DISK_ERR); /* Finalize the currtent secter write operation */ 974 | fs->flag &= ~FA__WIP; 975 | } 976 | } 977 | 978 | return FR_OK; 979 | } 980 | #endif 981 | 982 | 983 | 984 | /*-----------------------------------------------------------------------*/ 985 | /* Seek File R/W Pointer */ 986 | /*-----------------------------------------------------------------------*/ 987 | #if _USE_LSEEK 988 | 989 | FRESULT pf_lseek ( 990 | DWORD ofs /* File pointer from top of file */ 991 | ) 992 | { 993 | CLUST clst; 994 | DWORD bcs, sect, ifptr; 995 | FATFS *fs = FatFs; 996 | 997 | 998 | if (!fs) return FR_NOT_ENABLED; /* Check file system */ 999 | if (!(fs->flag & FA_OPENED)) /* Check if opened */ 1000 | return FR_NOT_OPENED; 1001 | 1002 | if (ofs > fs->fsize) ofs = fs->fsize; /* Clip offset with the file size */ 1003 | ifptr = fs->fptr; 1004 | fs->fptr = 0; 1005 | if (ofs > 0) { 1006 | bcs = (DWORD)fs->csize * 512; /* Cluster size (byte) */ 1007 | if (ifptr > 0 && 1008 | (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ 1009 | fs->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ 1010 | ofs -= fs->fptr; 1011 | clst = fs->curr_clust; 1012 | } else { /* When seek to back cluster, */ 1013 | clst = fs->org_clust; /* start from the first cluster */ 1014 | fs->curr_clust = clst; 1015 | } 1016 | while (ofs > bcs) { /* Cluster following loop */ 1017 | clst = get_fat(clst); /* Follow cluster chain */ 1018 | if (clst <= 1 || clst >= fs->n_fatent) ABORT(FR_DISK_ERR); 1019 | fs->curr_clust = clst; 1020 | fs->fptr += bcs; 1021 | ofs -= bcs; 1022 | } 1023 | fs->fptr += ofs; 1024 | sect = clust2sect(clst); /* Current sector */ 1025 | if (!sect) ABORT(FR_DISK_ERR); 1026 | fs->dsect = sect + (fs->fptr / 512 & (fs->csize - 1)); 1027 | } 1028 | 1029 | return FR_OK; 1030 | } 1031 | #endif 1032 | 1033 | 1034 | 1035 | /*-----------------------------------------------------------------------*/ 1036 | /* Create a Directroy Object */ 1037 | /*-----------------------------------------------------------------------*/ 1038 | #if _USE_DIR 1039 | 1040 | FRESULT pf_opendir ( 1041 | DIR *dj, /* Pointer to directory object to create */ 1042 | const char *path /* Pointer to the directory path */ 1043 | ) 1044 | { 1045 | FRESULT res; 1046 | BYTE sp[12], dir[32]; 1047 | FATFS *fs = FatFs; 1048 | 1049 | 1050 | if (!fs) { /* Check file system */ 1051 | res = FR_NOT_ENABLED; 1052 | } else { 1053 | dj->fn = sp; 1054 | res = follow_path(dj, dir, path); /* Follow the path to the directory */ 1055 | if (res == FR_OK) { /* Follow completed */ 1056 | if (dir[0]) { /* It is not the root dir */ 1057 | if (dir[DIR_Attr] & AM_DIR) /* The object is a directory */ 1058 | dj->sclust = get_clust(dir); 1059 | else /* The object is not a directory */ 1060 | res = FR_NO_FILE; 1061 | } 1062 | if (res == FR_OK) 1063 | res = dir_rewind(dj); /* Rewind dir */ 1064 | } 1065 | } 1066 | 1067 | return res; 1068 | } 1069 | 1070 | 1071 | 1072 | 1073 | /*-----------------------------------------------------------------------*/ 1074 | /* Read Directory Entry in Sequense */ 1075 | /*-----------------------------------------------------------------------*/ 1076 | 1077 | FRESULT pf_readdir ( 1078 | DIR *dj, /* Pointer to the open directory object */ 1079 | FILINFO *fno /* Pointer to file information to return */ 1080 | ) 1081 | { 1082 | FRESULT res; 1083 | BYTE sp[12], dir[32]; 1084 | FATFS *fs = FatFs; 1085 | 1086 | 1087 | if (!fs) { /* Check file system */ 1088 | res = FR_NOT_ENABLED; 1089 | } else { 1090 | dj->fn = sp; 1091 | if (!fno) { 1092 | res = dir_rewind(dj); 1093 | } else { 1094 | res = dir_read(dj, dir); /* Get current directory item */ 1095 | if (res == FR_NO_FILE) res = FR_OK; 1096 | if (res == FR_OK) { /* A valid entry is found */ 1097 | get_fileinfo(dj, dir, fno); /* Get the object information */ 1098 | res = dir_next(dj); /* Increment read index for next */ 1099 | if (res == FR_NO_FILE) res = FR_OK; 1100 | } 1101 | } 1102 | } 1103 | 1104 | return res; 1105 | } 1106 | 1107 | #endif /* _USE_DIR */ 1108 | 1109 | -------------------------------------------------------------------------------- /pff/src/pff.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / Petit FatFs - FAT file system module include file R0.03 (C)ChaN, 2014 3 | /----------------------------------------------------------------------------/ 4 | / Petit FatFs module is an open source software to implement FAT file system to 5 | / small embedded systems. This is a free software and is opened for education, 6 | / research and commercial developments under license policy of following trems. 7 | / 8 | / Copyright (C) 2014, ChaN, all right reserved. 9 | / 10 | / * The Petit FatFs module is a free software and there is NO WARRANTY. 11 | / * No restriction on use. You can use, modify and redistribute it for 12 | / personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY. 13 | / * Redistributions of source code must retain the above copyright notice. 14 | / 15 | /----------------------------------------------------------------------------*/ 16 | 17 | #ifndef _PFATFS 18 | #define _PFATFS 4004 /* Revision ID */ 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #include "integer.h" 25 | #include "pffconf.h" 26 | 27 | #if _PFATFS != _PFFCONF 28 | #error Wrong configuration file (pffconf.h). 29 | #endif 30 | 31 | #if _FS_FAT32 32 | #define CLUST DWORD 33 | #else 34 | #define CLUST WORD 35 | #endif 36 | 37 | 38 | /* File system object structure */ 39 | 40 | typedef struct { 41 | BYTE fs_type; /* FAT sub type */ 42 | BYTE flag; /* File status flags */ 43 | BYTE csize; /* Number of sectors per cluster */ 44 | BYTE pad1; 45 | WORD n_rootdir; /* Number of root directory entries (0 on FAT32) */ 46 | CLUST n_fatent; /* Number of FAT entries (= number of clusters + 2) */ 47 | DWORD fatbase; /* FAT start sector */ 48 | DWORD dirbase; /* Root directory start sector (Cluster# on FAT32) */ 49 | DWORD database; /* Data start sector */ 50 | DWORD fptr; /* File R/W pointer */ 51 | DWORD fsize; /* File size */ 52 | CLUST org_clust; /* File start cluster */ 53 | CLUST curr_clust; /* File current cluster */ 54 | DWORD dsect; /* File current data sector */ 55 | } FATFS; 56 | 57 | 58 | 59 | /* Directory object structure */ 60 | 61 | typedef struct { 62 | WORD index; /* Current read/write index number */ 63 | BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ 64 | CLUST sclust; /* Table start cluster (0:Static table) */ 65 | CLUST clust; /* Current cluster */ 66 | DWORD sect; /* Current sector */ 67 | } DIR; 68 | 69 | 70 | 71 | /* File status structure */ 72 | 73 | typedef struct { 74 | DWORD fsize; /* File size */ 75 | WORD fdate; /* Last modified date */ 76 | WORD ftime; /* Last modified time */ 77 | BYTE fattrib; /* Attribute */ 78 | char fname[13]; /* File name */ 79 | } FILINFO; 80 | 81 | 82 | 83 | /* File function return code (FRESULT) */ 84 | 85 | typedef enum { 86 | FR_OK = 0, /* 0 */ 87 | FR_DISK_ERR, /* 1 */ 88 | FR_NOT_READY, /* 2 */ 89 | FR_NO_FILE, /* 3 */ 90 | FR_NOT_OPENED, /* 4 */ 91 | FR_NOT_ENABLED, /* 5 */ 92 | FR_NO_FILESYSTEM /* 6 */ 93 | } FRESULT; 94 | 95 | 96 | 97 | /*--------------------------------------------------------------*/ 98 | /* Petit FatFs module application interface */ 99 | 100 | FRESULT pf_mount (FATFS* fs); /* Mount/Unmount a logical drive */ 101 | FRESULT pf_open (const char* path); /* Open a file */ 102 | FRESULT pf_read (void* buff, UINT btr, UINT* br); /* Read data from the open file */ 103 | FRESULT pf_write (const void* buff, UINT btw, UINT* bw); /* Write data to the open file */ 104 | FRESULT pf_lseek (DWORD ofs); /* Move file pointer of the open file */ 105 | FRESULT pf_opendir (DIR* dj, const char* path); /* Open a directory */ 106 | FRESULT pf_readdir (DIR* dj, FILINFO* fno); /* Read a directory item from the open directory */ 107 | 108 | 109 | 110 | /*--------------------------------------------------------------*/ 111 | /* Flags and offset address */ 112 | 113 | /* File status flag (FATFS.flag) */ 114 | 115 | #define FA_OPENED 0x01 116 | #define FA_WPRT 0x02 117 | #define FA__WIP 0x40 118 | 119 | 120 | /* FAT sub type (FATFS.fs_type) */ 121 | 122 | #define FS_FAT12 1 123 | #define FS_FAT16 2 124 | #define FS_FAT32 3 125 | 126 | 127 | /* File attribute bits for directory entry */ 128 | 129 | #define AM_RDO 0x01 /* Read only */ 130 | #define AM_HID 0x02 /* Hidden */ 131 | #define AM_SYS 0x04 /* System */ 132 | #define AM_VOL 0x08 /* Volume label */ 133 | #define AM_LFN 0x0F /* LFN entry */ 134 | #define AM_DIR 0x10 /* Directory */ 135 | #define AM_ARC 0x20 /* Archive */ 136 | #define AM_MASK 0x3F /* Mask of defined bits */ 137 | 138 | 139 | /*--------------------------------*/ 140 | /* Multi-byte word access macros */ 141 | 142 | #if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ 143 | #define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) 144 | #define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) 145 | #define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) 146 | #define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) 147 | #else /* Use byte-by-byte access to the FAT structure */ 148 | #define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) 149 | #define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) 150 | #define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) 151 | #define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) 152 | #endif 153 | 154 | 155 | #ifdef __cplusplus 156 | } 157 | #endif 158 | 159 | #endif /* _PFATFS */ 160 | -------------------------------------------------------------------------------- /pff/src/pffconf.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / Petit FatFs - Configuration file R0.03 (C)ChaN, 2014 3 | /---------------------------------------------------------------------------*/ 4 | 5 | #ifndef _PFFCONF 6 | #define _PFFCONF 4004 /* Revision ID */ 7 | 8 | /*---------------------------------------------------------------------------/ 9 | / Function Configurations 10 | /---------------------------------------------------------------------------*/ 11 | 12 | #define _USE_READ 1 /* Enable pf_read() function */ 13 | #define _USE_DIR 0 /* Enable pf_opendir() and pf_readdir() function */ 14 | #define _USE_LSEEK 0 /* Enable pf_lseek() function */ 15 | #define _USE_WRITE 0 /* Enable pf_write() function */ 16 | 17 | #define _FS_FAT12 0 /* Enable FAT12 */ 18 | #define _FS_FAT16 1 /* Enable FAT16 */ 19 | #define _FS_FAT32 1 /* Enable FAT32 */ 20 | 21 | 22 | /*---------------------------------------------------------------------------/ 23 | / Locale and Namespace Configurations 24 | /---------------------------------------------------------------------------*/ 25 | 26 | #define _USE_LCC 0 /* Allow lower case characters for path name */ 27 | 28 | #define _CODE_PAGE 437 29 | /* The _CODE_PAGE specifies the code page to be used on the target system. 30 | / SBCS code pages with _USE_LCC == 1 requiers a 128 byte of case conversion 31 | / table. This might occupy RAM on some platforms, e.g. avr-gcc. 32 | / When _USE_LCC == 0, _CODE_PAGE has no effect. 33 | / 34 | / 932 - Japanese Shift_JIS (DBCS, OEM, Windows) 35 | / 936 - Simplified Chinese GBK (DBCS, OEM, Windows) 36 | / 949 - Korean (DBCS, OEM, Windows) 37 | / 950 - Traditional Chinese Big5 (DBCS, OEM, Windows) 38 | / 1250 - Central Europe (Windows) 39 | / 1251 - Cyrillic (Windows) 40 | / 1252 - Latin 1 (Windows) 41 | / 1253 - Greek (Windows) 42 | / 1254 - Turkish (Windows) 43 | / 1255 - Hebrew (Windows) 44 | / 1256 - Arabic (Windows) 45 | / 1257 - Baltic (Windows) 46 | / 1258 - Vietnam (OEM, Windows) 47 | / 437 - U.S. (OEM) 48 | / 720 - Arabic (OEM) 49 | / 737 - Greek (OEM) 50 | / 775 - Baltic (OEM) 51 | / 850 - Multilingual Latin 1 (OEM) 52 | / 858 - Multilingual Latin 1 + Euro (OEM) 53 | / 852 - Latin 2 (OEM) 54 | / 855 - Cyrillic (OEM) 55 | / 866 - Russian (OEM) 56 | / 857 - Turkish (OEM) 57 | / 862 - Hebrew (OEM) 58 | / 874 - Thai (OEM, Windows) 59 | */ 60 | 61 | 62 | /*---------------------------------------------------------------------------/ 63 | / System Configurations 64 | /---------------------------------------------------------------------------*/ 65 | 66 | #define _WORD_ACCESS 1 67 | /* The _WORD_ACCESS option is an only platform dependent option. It defines 68 | / which access method is used to the word data on the FAT volume. 69 | / 70 | / 0: Byte-by-byte access. Always compatible with all platforms. 71 | / 1: Word access. Do not choose this unless under both the following conditions. 72 | / 73 | / * Address misaligned memory access is always allowed for ALL instructions. 74 | / * Byte order on the memory is little-endian. 75 | / 76 | / If it is the case, _WORD_ACCESS can also be set to 1 to improve performance and 77 | / reduce code size. Following table shows an example of some processor types. 78 | / 79 | / ARM7TDMI 0 ColdFire 0 V850E 0 80 | / Cortex-M3 0 Z80 0/1 V850ES 0/1 81 | / Cortex-M0 0 RX600(LE) 0/1 TLCS-870 0/1 82 | / AVR 0/1 RX600(BE) 0 TLCS-900 0/1 83 | / AVR32 0 RL78 0 R32C 0 84 | / PIC18 0/1 SH-2 0 M16C 0/1 85 | / PIC24 0 H8S 0 MSP430 0 86 | / PIC32 0 H8/300H 0 x86 0/1 87 | */ 88 | 89 | #endif /* _PFFCONF */ 90 | -------------------------------------------------------------------------------- /spi_pins.h: -------------------------------------------------------------------------------- 1 | // MOSI, MISO, and SCK pin definitions for all standard ATmega microcontrollers 2 | #ifndef SPI_PINS_H 3 | #define SPI_PINS_H 4 | 5 | #if defined(__AVR_ATmega64__) || defined(__AVR_ATmega64A__) || defined(__AVR_ATmega128__) || defined(__AVR_ATmega128A__) || \ 6 | defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || \ 7 | defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) || \ 8 | defined(__AVR_ATmega165__) || defined(__AVR_ATmega165A__) || defined(__AVR_ATmega165P__) || defined(__AVR_ATmega165PA__) || defined(__AVR_ATmega325__) ||defined(__AVR_ATmega325A__) || defined(__AVR_ATmega325P__) || defined(__AVR_ATmega325PA__) || defined(__AVR_ATmega645__) || defined(__AVR_ATmega645A__) || defined(__AVR_ATmega645P__) || \ 9 | defined(__AVR_ATmega3250__) || defined(__AVR_ATmega3250A__) || defined(__AVR_ATmega3250P__) || defined(__AVR_ATmega3250PA__) || defined(__AVR_ATmega6450__) || defined(__AVR_ATmega6450A__) || defined(__AVR_ATmega6450P__) || \ 10 | defined(__AVR_ATmega169__) || defined(__AVR_ATmega169A__) || defined(__AVR_ATmega169P__) || defined(__AVR_ATmega169PA__) || defined(__AVR_ATmega329__) || defined(__AVR_ATmega329A__) || defined(__AVR_ATmega329P__) || defined(__AVR_ATmega329PA__) || defined(__AVR_ATmega3290__) || defined(__AVR_ATmega3290A__) || defined(__AVR_ATmega3290P__) || defined(__AVR_ATmega3290PA__) || defined(__AVR_ATmega649__) || defined(__AVR_ATmega649A__) || defined(__AVR_ATmega649P__) || defined(__AVR_ATmega6490__) || defined(__AVR_ATmega6490A__) || defined(__AVR_ATmega6490P__) || \ 11 | defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32U6__) || \ 12 | defined(__AVR_AT90CAN32__ ) || defined(__AVR_AT90CAN64__ ) || defined(__AVR_AT90CAN128__ ) || \ 13 | defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) 14 | #define DDR_DI _SFR_IO_ADDR(DDRB), 2 //MMC DI MOSI pin (DDR, PORT) 15 | #define PORT_DI _SFR_IO_ADDR(PORTB), 2 16 | 17 | #define PIN_DO _SFR_IO_ADDR(PINB), 3 //MMC DO MISO pin (PIN, PORT) 18 | #define PORT_DO _SFR_IO_ADDR(PORTB), 3 19 | 20 | #define DDR_CK _SFR_IO_ADDR(DDRB), 1 //MMC SCK pin (DDR, PORT) 21 | #define PORT_CK _SFR_IO_ADDR(PORTB), 1 22 | 23 | 24 | #elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega8A__) || defined(__AVR_ATmega48__) || defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega48PB__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega88PB__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega168PB__) ||defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) 25 | #define DDR_DI _SFR_IO_ADDR(DDRB), 3 26 | #define PORT_DI _SFR_IO_ADDR(PORTB), 3 27 | 28 | #define PIN_DO _SFR_IO_ADDR(PINB), 4 29 | #define PORT_DO _SFR_IO_ADDR(PORTB), 4 30 | 31 | #define DDR_CK _SFR_IO_ADDR(DDRB), 5 32 | #define PORT_CK _SFR_IO_ADDR(PORTB), 5 33 | 34 | 35 | #elif defined(__AVR_ATmega16__) || defined(__AVR_ATmega16A__) || defined(__AVR_ATmega32__) || defined(__AVR_ATmega32A__) || \ 36 | defined(__AVR_ATmega161__) || defined(__AVR_ATmega162__) || defined(__AVR_ATmega163__) || \ 37 | defined(__AVR_ATmega164A__) || defined(__AVR_ATmega164P__) || defined(__AVR_ATmega164PA__) || defined(__AVR_ATmega323__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || \ 38 | defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) 39 | #define DDR_DI _SFR_IO_ADDR(DDRB), 5 40 | #define PORT_DI _SFR_IO_ADDR(PORTB), 5 41 | 42 | #define PIN_DO _SFR_IO_ADDR(PINB), 6 43 | #define PORT_DO _SFR_IO_ADDR(PORTB), 6 44 | 45 | #define DDR_CK _SFR_IO_ADDR(DDRB), 7 46 | #define PORT_CK _SFR_IO_ADDR(PORTB), 7 47 | 48 | 49 | #elif defined(__AVR_ATmega16M1__) || defined(__AVR_ATmega32M1__) || defined(__AVR_ATmega64M1__) || defined(__AVR_ATmega32C1__) || defined(__AVR_ATmega64C1__) || \ 50 | defined(__AVR_AT90PWM1__) || defined(__AVR_AT90PWM2__) || defined(__AVR_AT90PWM2B__) || defined(__AVR_AT90PWM3__) || defined(__AVR_AT90PWM3B__) || defined(__AVR_AT90PWM216__) || defined(__AVR_AT90PWM316__) 51 | #define DDR_DI _SFR_IO_ADDR(DDRB), 1 52 | #define PORT_DI _SFR_IO_ADDR(PORTB), 1 53 | 54 | #define PIN_DO _SFR_IO_ADDR(PINB), 0 55 | #define PORT_DO _SFR_IO_ADDR(PORTB), 0 56 | 57 | #define DDR_CK _SFR_IO_ADDR(DDRB), 7 58 | #define PORT_CK _SFR_IO_ADDR(PORTB), 7 59 | 60 | 61 | #elif defined(__AVR_AT90PWM81__) || defined(__AVR_AT90PWM161__) 62 | #define DDR_DI _SFR_IO_ADDR(DDRB), 4 63 | #define PORT_DI _SFR_IO_ADDR(PORTB), 4 64 | 65 | #define PIN_DO _SFR_IO_ADDR(PINB), 6 66 | #define PORT_DO _SFR_IO_ADDR(PORTB), 6 67 | 68 | #define DDR_CK _SFR_IO_ADDR(DDRB), 5 69 | #define PORT_CK _SFR_IO_ADDR(PORTB), 5 70 | 71 | 72 | #else 73 | #error SPI pins not defined for your processor. You must modify spi_pins.h 74 | #endif 75 | 76 | #endif //SPI_PINS_H 77 | -------------------------------------------------------------------------------- /uart/uart.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** This is a simple set of UART routines for debug purposes 3 | ** It's Tx only and the baud rate is fixed (see UART_init) 4 | */ 5 | 6 | #include "uart.h" 7 | #define UCSRA UCSR0A 8 | #define UCSRB UCSR0B 9 | #define UCSRC UCSR0C 10 | #define UBRRH UBRR0H 11 | #define UBRRL UBRR0L 12 | #define UDRE UDRE0 13 | #define UDR UDR0 14 | #define RXC RXC0 15 | 16 | #if BOOT_ADR > 0xFFFF 17 | #define PGM_READ_BYTE(x) pgm_read_byte_far(x) 18 | #else 19 | #define PGM_READ_BYTE(x) pgm_read_byte(x) 20 | #endif 21 | 22 | // Just enable the UART Tx and set baud rate for 38400 on 3.6864MHz (STK500) 23 | 24 | void UART_init(void) { 25 | UCSRB = (1 << TXEN0); 26 | UBRRL = USE_UART; // SEE HERE: http://wormfood.net/avrbaudcalc.php 27 | } 28 | 29 | // The classic Tx one character routine 30 | void UART_put(uint8_t c) { 31 | while (!(UCSRA & (1 << UDRE))); 32 | UDR = c; 33 | } 34 | 35 | // classic Tx a C-string routine 36 | // As there is no .data (in the bootloader) it only makes sense for theis to use PSTR() 37 | void UART_puts(const char * str) { 38 | char c; 39 | do { 40 | c = PGM_READ_BYTE(str++); 41 | if (c) { 42 | UART_put(c); 43 | } 44 | } while (c != 0); 45 | } 46 | 47 | // Just outputs "\r\n" 48 | void UART_newline(void){ 49 | UART_put('\r'); 50 | UART_put('\n'); 51 | } 52 | 53 | // used in printing a 2 digit hex number, outputs one of the two nibbles 54 | // the parameter is expected to be 0..F 55 | void UART_putnibble(uint8_t c) { 56 | if (c < 10) { 57 | UART_put('0' + c); 58 | } 59 | else { 60 | UART_put('A' + c - 10); 61 | } 62 | } 63 | 64 | // print both nibbles of an 8 bit hex number 65 | void UART_puthex(uint8_t c) { 66 | UART_putnibble(c >> 4); 67 | UART_putnibble(c & 0x0F); 68 | } 69 | 70 | // print both bytes of a 16 bit hex number 71 | void UART_puthex16(uint16_t n) { 72 | UART_puthex(n >> 8); 73 | UART_puthex(n & 0xFF); 74 | } 75 | // print both bytes of a 32 bit hex number 76 | void UART_puthex32(uint32_t n) { 77 | UART_puthex(n >> 24); 78 | UART_puthex(n >> 16 & 0xFF); 79 | UART_puthex(n >> 8 & 0xFF); 80 | UART_puthex(n & 0xFF); 81 | } 82 | 83 | // this expect the first parameter to be a string in dlash (that is PSTR()) 84 | // and then the second to be a value to print out in hex. typically used in 85 | // the form UART_putsP(PSTR("SecPerClus = "), SecPerClus) 86 | void UART_putsP(const char * str, uint16_t n) { 87 | UART_puts(str); 88 | UART_puthex16(n); 89 | UART_newline(); 90 | } 91 | 92 | // dump the 512 bytes at the given address in the form: 93 | // CD BF 10 E0 A0 E6 B0 E0 E4 E5 F0 E0 02 C0 05 90 Ϳ ������� � � 94 | void UART_dumpsector(uint8_t * Buff) { 95 | for (uint16_t i=0; i<512; i++) { 96 | if ((i % 16) == 0) { 97 | UART_put(' '); 98 | for(uint16_t j=(i -16); j<=i; j++) { 99 | UART_put(((Buff[j]>=(uint8_t)32) && (Buff[j]<(uint8_t)127)) ? Buff[j] : '.'); 100 | } 101 | UART_newline(); 102 | } 103 | UART_puthex(Buff[i]); 104 | UART_put(' '); 105 | } 106 | UART_newline(); 107 | } 108 | -------------------------------------------------------------------------------- /uart/uart.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | ** This is a simple set of UART routines for debug purposes 6 | ** It's Tx only and the baud rate is fixed (see UART_init) 7 | */ 8 | 9 | // Just enable the UART Tx and set baud rate for 38400 on 3.6864MHz (STK500) 10 | void UART_init(void); 11 | // The classic Tx one character routine 12 | void UART_put(uint8_t c); 13 | // classic Tx a C-string routine (string in PROGMEM) 14 | void UART_puts(const char * str); 15 | // this expect the first parameter to be a string in dlash (that is PSTR()) 16 | // and then the second to be a value to print out in hex. typically used in 17 | // the form UART_putsP(PSTR("SecPerClus = "), SecPerClus) 18 | void UART_putsP(const char * str, uint16_t n); 19 | // Just outputs "\r\n" 20 | void UART_newline(void); 21 | // used in printing a 2 digit hex number, outputs one of the two nibbles 22 | // the parameter is expected to be 0..F 23 | void UART_putnibble(uint8_t c); 24 | // print both nibbles of an 8 bit hex number 25 | void UART_puthex(uint8_t c); 26 | // print both bytes of a 16 bit hex number 27 | void UART_puthex16(uint16_t n); 28 | // print both bytes of a 32 bit hex number 29 | void UART_puthex32(uint32_t n); 30 | // dump the 512 bytes at the given address in the form: 31 | // CD BF 10 E0 A0 E6 B0 E0 E4 E5 F0 E0 02 C0 05 90 Ϳ ������� � � 32 | void UART_dumpsector(uint8_t * Buff); 33 | --------------------------------------------------------------------------------