├── Makefile ├── README.md ├── diskio.h ├── electron_branchtable.S ├── electron_build_branchtable.sh ├── ff.c ├── ff.h ├── ffconf.h ├── ffunicode.c ├── integer.h ├── interrupt.S ├── main.c ├── main.h ├── roms-preloaded-from-flash.S ├── roms ├── README.md └── blank.rom ├── sdmm.c ├── startup_stm32f4xx.s ├── stm32_flash.ld ├── stm32f4xx_conf.h ├── system_stm32f4xx.c └── transfer.sh /Makefile: -------------------------------------------------------------------------------- 1 | # example disassemble 2 | # arm-none-eabi-objdump -dS stm32f4-rom-emulator.elf >asm.out 3 | 4 | # Put your stlink folder here so make burn will work. 5 | STLINK=~/stlink.git 6 | 7 | #SRCS=main.c system_stm32f4xx.c stm32f4xx_it.c 8 | #SRCS=main.c system_stm32f4xx.c working-stm32f4xx_it.c 9 | 10 | # 11 | # 12 | SRCS=ff.c ffunicode.c sdmm.c main.c system_stm32f4xx.c 13 | 14 | # Library modules 15 | SRCS += stm32f4xx_syscfg.c misc.c stm32f4xx_gpio.c stm32f4xx_rcc.c stm32f4xx_usart.c stm32f4xx_exti.c stm32f4xx_pwr.c stm32f4xx_adc.c 16 | #SRCS += stm32f4xx_tim.c 17 | #SRCS += stm32f4_discovery.c 18 | 19 | # Binaries will be generated with this name (.elf, .bin, .hex, etc) 20 | PROJ_NAME=electron-rom-emulator 21 | 22 | ####################################################################################### 23 | 24 | #STM_COMMON=../../.. 25 | # You need libs somewhere! 26 | STM_COMMON=../STM32F4-Discovery_FW_V1.1.0 27 | 28 | CC=arm-none-eabi-gcc 29 | OBJCOPY=arm-none-eabi-objcopy 30 | 31 | #CFLAGS = -g -O2 -Wall -Tstm32_flash.ld 32 | CFLAGS = -g -O2 -Wall -Tstm32_flash.ld 33 | CFLAGS += -DUSE_STDPERIPH_DRIVER 34 | CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork 35 | CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 36 | CFLAGS += -I. 37 | #CFLAGS += --specs=nosys.specs 38 | CFLAGS += -specs=nano.specs -specs=rdimon.specs -lc -lrdimon 39 | ## Even though we specify these registers in main.c as global, still need to specify here to stop FATFS and anything else using though (though we luck out with any other libs linked in) 40 | CFLAGS += -ffixed-s0 41 | CFLAGS += -ffixed-s1 42 | CFLAGS += -ffixed-s2 43 | CFLAGS += -ffixed-s3 44 | CFLAGS += -ffixed-s4 45 | CFLAGS += -ffixed-s5 46 | CFLAGS += -ffixed-s6 47 | CFLAGS += -ffixed-s7 48 | CFLAGS += -ffixed-s8 49 | CFLAGS += -ffixed-s9 50 | CFLAGS += -ffixed-s30 51 | 52 | 53 | # NB: You have to have DEBUG_OUPUT_ON_GPIOA set in order to see any output on PA0 54 | #CFLAGS += -DDEBUG_OUTPUT_ON_GPIOA 55 | #CFLAGS += -DDEBUG_EXTI0_START -DDEBUG_EXTI0_END 56 | #CFLAGS += -DDEBUG_EXTI0_ROM_ACCESS 57 | #CFLAGS += -DDEBUG_EXTI0_SWRAM_WRITE 58 | #CFLAGS += -DDEBUG_FE05 59 | #CFLAGS += -DDEBUG_FC71 60 | #CFLAGS += -DDEBUG_FC72 61 | # If you board has an SD card slot with pullups, then set DISABLE_PULLUPS_FOR_SDCARD 62 | #CFLAGS += -DDISABLE_PULLUPS_FOR_SDCARD 63 | #CFLAGS += -DDEBUG_ADC 64 | #CFLAGS += -DENABLE_SEMIHOSTING 65 | 66 | # Include files from STM libraries 67 | CFLAGS += -I$(STM_COMMON)/Utilities/STM32F4-Discovery 68 | CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/Include 69 | CFLAGS += -I$(STM_COMMON)/Libraries/CMSIS/ST/STM32F4xx/Include 70 | CFLAGS += -I$(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/inc 71 | 72 | 73 | # add startup file to build 74 | SRCS += startup_stm32f4xx.s 75 | # You need to end asm files in capital S to get them to see preprocessor directives 76 | SRCS += interrupt.S 77 | 78 | OBJS = $(SRCS:.c=.o) 79 | 80 | vpath %.c $(STM_COMMON)/Libraries/STM32F4xx_StdPeriph_Driver/src $(STM_COMMON)/Utilities/STM32F4-Discovery 81 | 82 | .PHONY: proj 83 | 84 | all: proj 85 | 86 | proj: $(PROJ_NAME).elf 87 | 88 | $(PROJ_NAME).elf: $(SRCS) 89 | $(CC) $(CFLAGS) $^ -o $@ 90 | $(OBJCOPY) -O ihex $(PROJ_NAME).elf $(PROJ_NAME).hex 91 | $(OBJCOPY) -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin 92 | 93 | clean: 94 | rm -f *.o 95 | rm -f $(PROJ_NAME).elf 96 | rm -f $(PROJ_NAME).hex 97 | rm -f $(PROJ_NAME).bin 98 | 99 | 100 | # Flash the STM32F4 101 | #burn: proj 102 | # $(STLINK)/st-flash write $(PROJ_NAME).bin 0x8000000 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Electron ROM Emulator 2 | ===================== 3 | kernel at kernelcrash dot com 4 | More details on this at www.kernelcrash.com 5 | 6 | Overview 7 | ======== 8 | 9 | - A bit like an Electron Plus 1 specifically set up for hooking an SD card onto it and 10 | using the MMFS ROM https://github.com/hoglet67/MMFS, but should be able to emulate any 11 | 16KB Electron ROM 12 | - Uses a cheap STM32F407 board directly into the expansion connector of the Electron. 13 | Most F407 pins are 5V tolerant. Some of these boards have a micro SD card slot, or you 14 | can wire a micro SD socket in. 15 | - Emulates 8 ROM slots (slots 4, 5, 6, 7 and 12, 13, 14 and 15) but they all act as sideways RAM slots 16 | - Can load rom files directly from flash on the stm32f407. This requires you to 'compile 17 | the roms in'. See Troubleshooting further down for how to do this. 18 | - Loads 16KB rom files from an SD card on boot. You need a directory on your FAT32 sdcard like so: 19 | ``` 20 | boot/4 21 | boot/5 22 | boot/6 23 | boot/7 24 | boot/12/ESWMMFS.rom 25 | boot/13 26 | boot/14 27 | boot/15 28 | ``` 29 | ie. Put one rom file in the boot/12 directory, and it will be loaded into rom slot 12 30 | on boot. Put one rom in boot/13 and it will be loaded into slot 13 etc. 31 | 32 | - If one of the rom slots contains the Electron Plus 1 version of MMFS, then MMFS will 33 | 'see' the SD card attached to the STM32F407 board and look for a BEEB.MMB file on it. 34 | It's recommended to use the sideways ram version of MMFS (ESWMMFS.rom) as it sets 35 | PAGE = E00, which is more compatible with a lot of games compared to the standard 36 | EMMFS.rom . Note, MMFS has a very minimal FAT interface layer, so you should always 37 | format the SD card (the first partition), copy your BEEB.MMB onto it (doing this 38 | as the first filecopy to a freshly formatted SD card is pretty important), then make all 39 | the boot directories (eg. boot/12, boot/13 etc) and then copy the appropriate roms into those 40 | directories. 41 | 42 | - You can also dynamically insert roms off the SD card while the Electron is running. 43 | So after you've set up the roms you want on boot under 'boot', create a 'roms' directory 44 | in the root of the SD card. Then create numbered directories underneath it and put a single 45 | 16K rom in each directory. For example; 46 | ``` 47 | roms/1/Hopper.rom 48 | roms/2/Viewsheet.rom 49 | ``` 50 | So boot the Electron now with the SD card inserted. Let's says you want to insert Hopper 51 | into rom slot 15. 15 is 'F' in hex, so type this at the Electron prompt 52 | ``` 53 | ?&FC0F = 1 54 | ``` 55 | That tells it to take the rom in 'roms/1' and insert it into slot 15 (ie. 'F'). If I wanted 56 | to put Viewsheet in I would go '?&FC0F = 2' . If I wanted Hopper in slot 4 (ie. '4' ) 57 | instead then I would go : 58 | ``` 59 | ?&FC04 = 1 60 | ``` 61 | After you insert a ROM like this, you can ctrl-break to reboot the Electron, and hopefully 62 | you should be able to interact with the ROM. 63 | 64 | This interface is effectively a proof of concept for simple communication between the 65 | interupt and a main outer loop that runs on the stm32f4 board. 66 | 67 | Currently there are eight memory addresses that correspond to the 8 rom slots; 68 | ``` 69 | &FC04 - rom slot 4 70 | &FC05 - rom slot 5 71 | &FC06 - rom slot 6 72 | &FC07 - rom slot 7 73 | 74 | &FC0C - rom slot 12 75 | &FC0D - rom slot 13 76 | &FC0E - rom slot 14 77 | &FC0F - rom slot 15 78 | ``` 79 | 80 | - There are analog ports that operate like the Plus 1 joystick ports. They possibly operate 81 | a little differently: 82 | ``` 83 | PA2 - Analog channel 1 84 | PA3 - Analog channel 2 85 | PA4 - Analog channel 3 86 | PA5 - Analog channel 4 87 | 88 | PC2 - Fire button (bit 4 when you read &FC72) 89 | PC3 - Fire buton 2 (bit 5 when you read &FC72) 90 | ``` 91 | The analog ports are looking for a voltage between 0 and 3.3V. If you connect the centre pin 92 | of the joystick potentiometers to PA2 and PA3, and the other pins of the potentiometers to 93 | GND and 3.3V (ie they just act as a simple voltage divider) then it should work. There are some 94 | settings in main.h that allow you to 'jump to the extremes' of the analog range in case your 95 | joystick cannot go all the way to 0 or all the way to 255. For example, If you want any 96 | value less than 64 to return 0, and any value greater than 192 to return 255, then do this 97 | in main.h; 98 | ``` 99 | #define ADC_LOW_THRESHOLD 64 100 | #define ADC_HIGH_THRESHOLD 192 101 | ``` 102 | 103 | Wiring 104 | ====== 105 | 106 | - Wiring from the 50 pin edge connector on the Electron to the STM42F407VET6 board is as follows 107 | ``` 108 | BOTTOM TOP (towards the AC INPUT) 109 | 110 | 2 1 111 | 4 3 112 | 6 5 113 | GND 8 7 GND 114 | +5V 10 9 +5V 115 | 12 11 116 | (PC0) Phi0 14 13 117 | 16 15 118 | (PC1) _R/W 18 17 119 | (PD14) D6 20 19 D7 (PD15) 120 | (PD12) D4 22 21 D5 (PD13) 121 | (PD10) D2 24 23 D3 (PD11) 122 | (PD8) D0 26 25 D1 (PD9) 123 | 28 27 124 | 30 29 125 | (PE14) A14 32 31 A15 (PE15) 126 | (PE12) A12 34 33 A13 (PE13) 127 | (PE10) A10 36 35 A11 (PE11) 128 | (PE0) A0 38 37 A9 (PE9) 129 | (PE2) A2 40 39 A1 (PE1) 130 | (PE4) A4 42 41 A3 (PE3) 131 | (PE6) A6 44 43 A5 (PE5) 132 | (PE8) A8 46 45 A7 (PE7) 133 | GND 48 47 GND 134 | +5V 50 49 +5V 135 | ``` 136 | 137 | - Some STM32F407 boards have an SD card slot and already wired in 138 | the 'standard way' for SDIO . Otherwise wire up the SD card as follows; 139 | ``` 140 | /CS - PC11 141 | MOSI - PD2 142 | SCK - PC12 143 | 144 | MISO - PC8 145 | ``` 146 | Obviously connect the GND's up and remember that the SD card runs at 3.3V 147 | and should not have a level converter between the stm32f407 and the card. 148 | 149 | Technical 150 | ========= 151 | 152 | An older version of this program sat in a tight timing loop watching the 153 | phi0 output of the Electron. Phi0 is effectively the clock for the Electron. 154 | It is 'mostly 2MHz' but will slow down when accessing peripherals or RAM. 155 | 156 | So that version watched for phi0 going high, read the address lines of the 157 | 6502, worked out if it was a sideways rom access, presented a byte from 158 | the STM32's flash rom, left it long enough on the databus for the 6502 159 | to read it, then quickly tri-stated the databus again ... and waited for 160 | next rising edge of phi0. 161 | 162 | This newer interrupt version connects phi0 to an interrupt on the STM32. 163 | Rather than interrupt on the rising edge of phi0 when the address bus 164 | would be known to be stable, the interrupt occurs on the negative edge 165 | of phi0 which is effectively the end of the previous cycle. 166 | 167 | The reason for doing this is that it takes time to respond to an interrupt, 168 | so the latency between an 'edge' that causes an interrupt and the first 169 | executing line of an interrupt service routine (ISR) is at least 100ns, 170 | but more like 150ns ... but can be higher. If the first executing line of 171 | the ISR occurred 150ns after the positive edge, then it would be too 172 | late to do anything useful (the 100ns or so left is not a lot of instructions). 173 | 174 | So we interrupt on the negative edge and the ISR routine goes like this; 175 | 176 | - The first line of the ISR is maybe 100 - 150ns later in the low part 177 | of phi0 178 | - We poll for phi0 going high. While we are polling we are also grabbing 179 | the address on the address bus and the state of the 6502 read/_write 180 | line. 181 | - Once we detect phi0 high, we look at the address bus and read/_write 182 | line to try to figure out whether its a memory access for our sideways 183 | ram slots or some of the IO registers in a 'Plus 1' that we are 184 | emulating. 185 | - More importantly we try to exit the ISR if we dont need to do anything. 186 | eg. a RAM access. Trying to exit early is important to give time 187 | back to the main thread in main.c (the while loop at the end). 188 | - But if its a request for us, then we do whats appropriate. The most 189 | common thing is for a ROM access in the 8000-BFFF range. We keep 190 | a sideways ROM register, such that if this register has been set to 191 | say '12' and then there was an access between 8000-BFFF, then we 192 | know we need to present a byte from a ROM. 193 | 194 | Grabbing the byte from RAM or ROM in the STM32 is the easy part. 195 | But we need to un-tristate the databus lines, put the associated 196 | byte on the databus lines, then wait for phi0 to end. To do that 197 | as accurately as possible we use the wfe instruction to 'wait 198 | for an event'. The event we wait for is the next negative edge 199 | of phi0. Once we get that edge, we immediately tri-state the 200 | databus lines and loop back to polling for phi0 going high. Some 201 | key points here; 202 | 203 | - because we are in an ISR routine this falling edge does 204 | not cause another interrupt. 205 | - We don't exit the ISR. Effectively we 'loop round' and 206 | watch for the next positive edge. We don't end iup looping 207 | around forever as we will eventually hit a RAM access or 208 | upper ROM/peripherals access that will allow us to exit 209 | the ISR. 210 | 211 | Still this is a miniscule amount of time to service an interrupt. Key stuff: 212 | 213 | - memory and IO accesses consume more time than you think 214 | - branches consume more time than you think 215 | - ARM will automatically push r0,r1,r2,r3 and r12 on entry to the ISR and 216 | pop them when you leave. You can obviously push and pop additional registers, 217 | but because push and pop are memory operations, there is a fair time penalty 218 | to do that. 219 | - The stm32f407 has a Floating Point Unit (FPU) and normally I would disable it 220 | as I don't use any floating point operations. However, it has 32 x 32bit 221 | registers (s0 to s31) . These are generally used for floating point math, 222 | but you can move them to and from normal registers, and you can also store them 223 | to memory locations (using a regular register for an address base) 224 | - So now I use lots of FPU registers to store 'global values' used by the ISR. This 225 | way the ISR does not need to load these from memory during the ISR. eg. register s3 226 | is used to store the base address for EXTI (used by lots of interrupt related activities). 227 | We are also often using the values 0 and 1, so two registers are effectively wasted as 228 | constants for 0 and 1 (in my case s0 = 0 and s1 = 1). eg. 229 | ``` 230 | vmov r3,s3 // r3 = EXTI 231 | vstr s1,[r3,PR] // clear interrupt by writing 1 to it. 232 | ``` 233 | Compiling 234 | ========= 235 | 236 | You need the ST standard peripheral library. I used the STSW-STM32068 237 | firmware package for the stmf4 Discovery from st.com. In the Makefile ST_COMMON 238 | needs to point to it. 239 | 240 | You need an ARM GCC build chain in your path. 241 | 242 | Generally you put your roms on the SD card, but there is way to load some from 243 | internal flash (see troubleshooting notes further down). 244 | 245 | Do a 246 | ``` 247 | make 248 | ``` 249 | Look at transfer.sh for how you might transfer it to your board. 250 | 251 | 252 | Troubleshooting 253 | =============== 254 | 255 | If you have trouble with the roms loading from SD card , check a few things 256 | - Preferably the SD card is a smaller and/or older one. In 2019, I tend to buy cheap 257 | 8GB cards as they are about the smallest you can get. Buy the slowest you can find. 258 | - Partition the SD card so there is one partition and its less than 4GB (I tend 259 | to make a 1GB partition, but even that is overkill) 260 | - Format the partition with FAT32 . I am just using linux, and am not doing 261 | anything special (eg. sudo mkfs.vfat /dev/sd1 ) 262 | - Find a decent BEEB.MMB for the Electron on the stardot forums. 263 | - Copy the BEEB.MMB as the very first file you copy to your formatted SD card. 264 | MMFS has a minimal FAT layer, so I think I read that BEEB.MMB has to be one of 265 | the first 8 files written to the SD card (I could be wrong). 266 | - After you've copied the BEEB.MMB in, make the boot roms directories (eg. boot/12 , 267 | boot/13 etc) and copy some roms in. To keep it simple I would just copy ESWMMFS.rom into boot/12 and leave 268 | the other slots empty. One thing to note is that a different FAT interface runs on the stm32f407 269 | board and it does not have the same limitations as MMFS (all you need to know is MMFS wants to 270 | find BEEB.MMB. Any other files on the SD card are used directly by the stm32f407 board. 271 | - Try booting. If the SD card is too slow then you may not see any rom related banners when 272 | you boot the Electron. Try doing a ctrl-break on the Electron to get the Electron to boot 273 | without power cycling the stm32f407 board. 274 | 275 | - Normally when an SD card is initialised in SPI mode, it starts off with a slow 276 | clock and after an initialisation phase it switches to a faster clock. You can lock 277 | it in a slower clock if you think that is the problem. Look in sdmm.c for the 278 | disk_initialize method, and towards the end of it is this. 279 | 280 | BitDelay=0; 281 | 282 | Comment it out , and recompile. 283 | 284 | 285 | - The current code has two ways of loading ROMS as the system boots; 286 | 287 | - You reference one or more ROMS in roms-preloaded-from-flash.S 288 | - You put some ROMS inthe SD card under boot/4, boot/5, boot/6, boot/7, boot/12, boot/13, boot/14 or boot/15 289 | 290 | Both methods are attempted on boot in the order shown above. So let's say you defined two 291 | ROMs in roms-preloaded-from-flash.S, and they were defined to load as slot 12 and 13. 292 | But it you also put a ROM in boot/12 on the SD card, then slot 12 would be overridden with what you had 293 | on the SD card. Similarly slot 13 would be overridden in you had a ROM in boot/13 on 294 | the SD card and so on. 295 | 296 | To use preloading from flash, place the roms paths as incbin lines after the 297 | relevant slot labels in roms-preloaded-from-flash.S 298 | ``` 299 | slot_4_base: 300 | .incbin "roms/ESWMMFS.rom" 301 | slot_5_base: 302 | .incbin "roms/AP6v130ta.rom" 303 | slot_6_base: 304 | //.incbin "roms/blank.rom" 305 | slot_7_base: 306 | //.incbin "roms/blank.rom" 307 | 308 | ``` 309 | Obviously 'make' and flash the hex file to the stm32f407 board to use these. (you might need 310 | to do a 'make clean' then 'make') 311 | 312 | For reference the AP6v130ta.rom referred to above is the 16K AP6 rom from 313 | http://mdfs.net/Software/BBC/SROM/Plus1/ . That will give you a *ROMS 314 | command as well as various sideways ram load/save commands. I often put this as rom 13. 315 | 316 | - The flash accelerator had some problems in early stm32f4 chips. Find this line in main.c: 317 | ``` 318 | //FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; 319 | FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; 320 | ``` 321 | The line with FLASH_ACR_PRFTEN turns on the flash prefetch feature which is generally a good 322 | thing but might cause problems on some chips. You can try commenting one line and not the other to 323 | turn it on and off. 324 | 325 | 326 | 327 | -------------------------------------------------------------------------------- /diskio.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------- 2 | / 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 | /* Results of Disk Functions */ 19 | typedef enum { 20 | RES_OK = 0, /* 0: Successful */ 21 | RES_ERROR, /* 1: R/W Error */ 22 | RES_WRPRT, /* 2: Write Protected */ 23 | RES_NOTRDY, /* 3: Not Ready */ 24 | RES_PARERR /* 4: Invalid Parameter */ 25 | } DRESULT; 26 | 27 | 28 | /*---------------------------------------*/ 29 | /* Prototypes for disk control functions */ 30 | 31 | 32 | DSTATUS disk_initialize (BYTE pdrv); 33 | DSTATUS disk_status (BYTE pdrv); 34 | DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); 35 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); 36 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 37 | 38 | 39 | /* Disk Status Bits (DSTATUS) */ 40 | #define STA_NOINIT 0x01 /* Drive not initialized */ 41 | #define STA_NODISK 0x02 /* No medium in the drive */ 42 | #define STA_PROTECT 0x04 /* Write protected */ 43 | 44 | 45 | /* Command code for disk_ioctrl fucntion */ 46 | 47 | /* Generic command (Used by FatFs) */ 48 | #define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ 49 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ 50 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ 51 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ 52 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ 53 | 54 | /* Generic command (Not used by FatFs) */ 55 | #define CTRL_FORMAT 5 /* Create physical format on the media */ 56 | #define CTRL_POWER_IDLE 6 /* Put the device idle state */ 57 | #define CTRL_POWER_OFF 7 /* Put the device off state */ 58 | #define CTRL_LOCK 8 /* Lock media removal */ 59 | #define CTRL_UNLOCK 9 /* Unlock media removal */ 60 | #define CTRL_EJECT 10 /* Eject media */ 61 | #define CTRL_GET_SMART 11 /* Read SMART information */ 62 | 63 | /* MMC/SDC specific command (Not used by FatFs) */ 64 | #define MMC_GET_TYPE 50 /* Get card type */ 65 | #define MMC_GET_CSD 51 /* Read CSD */ 66 | #define MMC_GET_CID 52 /* Read CID */ 67 | #define MMC_GET_OCR 53 /* Read OCR */ 68 | #define MMC_GET_SDSTAT 54 /* Read SD status */ 69 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 70 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 71 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 72 | 73 | /* ATA/CF specific command (Not used by FatFs) */ 74 | #define ATA_GET_REV 60 /* Get F/W revision */ 75 | #define ATA_GET_MODEL 61 /* Get model name */ 76 | #define ATA_GET_SN 62 /* Get serial number */ 77 | 78 | 79 | /* MMC card type flags (MMC_GET_TYPE) */ 80 | #define CT_MMC 0x01 /* MMC ver 3 */ 81 | #define CT_SD1 0x02 /* SD ver 1 */ 82 | #define CT_SD2 0x04 /* SD ver 2 */ 83 | #define CT_SDC (CT_SD1|CT_SD2) /* SD */ 84 | #define CT_BLOCK 0x08 /* Block addressing */ 85 | 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /electron_build_branchtable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | address=0xfc00 3 | echo "branchtable:" 4 | while [ $address != "0x10000" ] 5 | do 6 | echo $address >&2 7 | JUMP=register_unused 8 | if [ "$address" = "0xfc71" -o "$address" = "0xfc72" -o "$address" = "0xfe05" ];then 9 | JUMP="register_$address" 10 | fi 11 | echo " .short (($JUMP - branchtable)/2) /* $address */" 12 | address="`printf '0x%X' $((address + 1))|tr '[:upper:]' '[:lower:]'`" 13 | 14 | done 15 | -------------------------------------------------------------------------------- /ff.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / FatFs - Generic FAT Filesystem module R0.13b / 3 | /-----------------------------------------------------------------------------/ 4 | / 5 | / Copyright (C) 2018, ChaN, all right reserved. 6 | / 7 | / FatFs module is an open source software. Redistribution and use of FatFs in 8 | / source and binary forms, with or without modification, are permitted provided 9 | / that the following condition is met: 10 | 11 | / 1. Redistributions of source code must retain the above copyright notice, 12 | / this condition and the following disclaimer. 13 | / 14 | / This software is provided by the copyright holder and contributors "AS IS" 15 | / and any warranties related to this software are DISCLAIMED. 16 | / The copyright owner or contributors be NOT LIABLE for any damages caused 17 | / by use of this software. 18 | / 19 | /----------------------------------------------------------------------------*/ 20 | 21 | 22 | #ifndef FF_DEFINED 23 | #define FF_DEFINED 63463 /* Revision ID */ 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #include "integer.h" /* Basic integer types */ 30 | #include "ffconf.h" /* FatFs configuration options */ 31 | 32 | #if FF_DEFINED != FFCONF_DEF 33 | #error Wrong configuration file (ffconf.h). 34 | #endif 35 | 36 | 37 | 38 | /* Definitions of volume management */ 39 | 40 | #if FF_MULTI_PARTITION /* Multiple partition configuration */ 41 | typedef struct { 42 | BYTE pd; /* Physical drive number */ 43 | BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ 44 | } PARTITION; 45 | extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ 46 | #endif 47 | 48 | #if FF_STR_VOLUME_ID 49 | #ifndef FF_VOLUME_STRS 50 | extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ 51 | #endif 52 | #endif 53 | 54 | 55 | 56 | /* Type of path name strings on FatFs API */ 57 | 58 | #ifndef _INC_TCHAR 59 | #define _INC_TCHAR 60 | 61 | #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ 62 | typedef WCHAR TCHAR; 63 | #define _T(x) L ## x 64 | #define _TEXT(x) L ## x 65 | #elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */ 66 | typedef char TCHAR; 67 | #define _T(x) u8 ## x 68 | #define _TEXT(x) u8 ## x 69 | #elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */ 70 | typedef DWORD TCHAR; 71 | #define _T(x) U ## x 72 | #define _TEXT(x) U ## x 73 | #elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3) 74 | #error Wrong FF_LFN_UNICODE setting 75 | #else /* ANSI/OEM code in SBCS/DBCS */ 76 | typedef char TCHAR; 77 | #define _T(x) x 78 | #define _TEXT(x) x 79 | #endif 80 | 81 | #endif 82 | 83 | 84 | 85 | /* Type of file size variables */ 86 | 87 | #if FF_FS_EXFAT 88 | typedef QWORD FSIZE_t; 89 | #else 90 | typedef DWORD FSIZE_t; 91 | #endif 92 | 93 | 94 | 95 | /* Filesystem object structure (FATFS) */ 96 | 97 | typedef struct { 98 | BYTE fs_type; /* Filesystem type (0:N/A) */ 99 | BYTE pdrv; /* Physical drive number */ 100 | BYTE n_fats; /* Number of FATs (1 or 2) */ 101 | BYTE wflag; /* win[] flag (b0:dirty) */ 102 | BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ 103 | WORD id; /* Volume mount ID */ 104 | WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ 105 | WORD csize; /* Cluster size [sectors] */ 106 | #if FF_MAX_SS != FF_MIN_SS 107 | WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ 108 | #endif 109 | #if FF_USE_LFN 110 | WCHAR* lfnbuf; /* LFN working buffer */ 111 | #endif 112 | #if FF_FS_EXFAT 113 | BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ 114 | #endif 115 | #if FF_FS_REENTRANT 116 | FF_SYNC_t sobj; /* Identifier of sync object */ 117 | #endif 118 | #if !FF_FS_READONLY 119 | DWORD last_clst; /* Last allocated cluster */ 120 | DWORD free_clst; /* Number of free clusters */ 121 | #endif 122 | #if FF_FS_RPATH 123 | DWORD cdir; /* Current directory start cluster (0:root) */ 124 | #if FF_FS_EXFAT 125 | DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ 126 | DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ 127 | DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ 128 | #endif 129 | #endif 130 | DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ 131 | DWORD fsize; /* Size of an FAT [sectors] */ 132 | DWORD volbase; /* Volume base sector */ 133 | DWORD fatbase; /* FAT base sector */ 134 | DWORD dirbase; /* Root directory base sector/cluster */ 135 | DWORD database; /* Data base sector */ 136 | DWORD winsect; /* Current sector appearing in the win[] */ 137 | BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ 138 | } FATFS; 139 | 140 | 141 | 142 | /* Object ID and allocation information (FFOBJID) */ 143 | 144 | typedef struct { 145 | FATFS* fs; /* Pointer to the hosting volume of this object */ 146 | WORD id; /* Hosting volume mount ID */ 147 | BYTE attr; /* Object attribute */ 148 | BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */ 149 | DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ 150 | FSIZE_t objsize; /* Object size (valid when sclust != 0) */ 151 | #if FF_FS_EXFAT 152 | DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ 153 | DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ 154 | DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ 155 | DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ 156 | DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ 157 | #endif 158 | #if FF_FS_LOCK 159 | UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ 160 | #endif 161 | } FFOBJID; 162 | 163 | 164 | 165 | /* File object structure (FIL) */ 166 | 167 | typedef struct { 168 | FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ 169 | BYTE flag; /* File status flags */ 170 | BYTE err; /* Abort flag (error code) */ 171 | FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ 172 | DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ 173 | DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ 174 | #if !FF_FS_READONLY 175 | DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ 176 | BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ 177 | #endif 178 | #if FF_USE_FASTSEEK 179 | DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ 180 | #endif 181 | #if !FF_FS_TINY 182 | BYTE buf[FF_MAX_SS]; /* File private data read/write window */ 183 | #endif 184 | } FIL; 185 | 186 | 187 | 188 | /* Directory object structure (DIR) */ 189 | 190 | typedef struct { 191 | FFOBJID obj; /* Object identifier */ 192 | DWORD dptr; /* Current read/write offset */ 193 | DWORD clust; /* Current cluster */ 194 | DWORD sect; /* Current sector (0:Read operation has terminated) */ 195 | BYTE* dir; /* Pointer to the directory item in the win[] */ 196 | BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ 197 | #if FF_USE_LFN 198 | DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ 199 | #endif 200 | #if FF_USE_FIND 201 | const TCHAR* pat; /* Pointer to the name matching pattern */ 202 | #endif 203 | } DIR; 204 | 205 | 206 | 207 | /* File information structure (FILINFO) */ 208 | 209 | typedef struct { 210 | FSIZE_t fsize; /* File size */ 211 | WORD fdate; /* Modified date */ 212 | WORD ftime; /* Modified time */ 213 | BYTE fattrib; /* File attribute */ 214 | #if FF_USE_LFN 215 | TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ 216 | TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ 217 | #else 218 | TCHAR fname[12 + 1]; /* File name */ 219 | #endif 220 | } FILINFO; 221 | 222 | 223 | 224 | /* File function return code (FRESULT) */ 225 | 226 | typedef enum { 227 | FR_OK = 0, /* (0) Succeeded */ 228 | FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ 229 | FR_INT_ERR, /* (2) Assertion failed */ 230 | FR_NOT_READY, /* (3) The physical drive cannot work */ 231 | FR_NO_FILE, /* (4) Could not find the file */ 232 | FR_NO_PATH, /* (5) Could not find the path */ 233 | FR_INVALID_NAME, /* (6) The path name format is invalid */ 234 | FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ 235 | FR_EXIST, /* (8) Access denied due to prohibited access */ 236 | FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ 237 | FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ 238 | FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ 239 | FR_NOT_ENABLED, /* (12) The volume has no work area */ 240 | FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ 241 | FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ 242 | FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ 243 | FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ 244 | FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ 245 | FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ 246 | FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ 247 | } FRESULT; 248 | 249 | 250 | 251 | /*--------------------------------------------------------------*/ 252 | /* FatFs module application interface */ 253 | 254 | FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ 255 | FRESULT f_close (FIL* fp); /* Close an open file object */ 256 | FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ 257 | FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ 258 | FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ 259 | FRESULT f_truncate (FIL* fp); /* Truncate the file */ 260 | FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ 261 | FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ 262 | FRESULT f_closedir (DIR* dp); /* Close an open directory */ 263 | FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ 264 | FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ 265 | FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ 266 | FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ 267 | FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ 268 | FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ 269 | FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ 270 | FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ 271 | FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ 272 | FRESULT f_chdir (const TCHAR* path); /* Change current directory */ 273 | FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ 274 | FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ 275 | FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ 276 | FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ 277 | FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ 278 | FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ 279 | FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ 280 | FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ 281 | FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ 282 | FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ 283 | FRESULT f_setcp (WORD cp); /* Set current code page */ 284 | int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ 285 | int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ 286 | int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ 287 | TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ 288 | 289 | #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) 290 | #define f_error(fp) ((fp)->err) 291 | #define f_tell(fp) ((fp)->fptr) 292 | #define f_size(fp) ((fp)->obj.objsize) 293 | #define f_rewind(fp) f_lseek((fp), 0) 294 | #define f_rewinddir(dp) f_readdir((dp), 0) 295 | #define f_rmdir(path) f_unlink(path) 296 | #define f_unmount(path) f_mount(0, path, 0) 297 | 298 | #ifndef EOF 299 | #define EOF (-1) 300 | #endif 301 | 302 | 303 | 304 | 305 | /*--------------------------------------------------------------*/ 306 | /* Additional user defined functions */ 307 | 308 | /* RTC function */ 309 | #if !FF_FS_READONLY && !FF_FS_NORTC 310 | DWORD get_fattime (void); 311 | #endif 312 | 313 | /* LFN support functions */ 314 | #if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ 315 | WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ 316 | WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ 317 | DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ 318 | #endif 319 | #if FF_USE_LFN == 3 /* Dynamic memory allocation */ 320 | void* ff_memalloc (UINT msize); /* Allocate memory block */ 321 | void ff_memfree (void* mblock); /* Free memory block */ 322 | #endif 323 | 324 | /* Sync functions */ 325 | #if FF_FS_REENTRANT 326 | int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ 327 | int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ 328 | void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ 329 | int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ 330 | #endif 331 | 332 | 333 | 334 | 335 | /*--------------------------------------------------------------*/ 336 | /* Flags and offset address */ 337 | 338 | 339 | /* File access mode and open method flags (3rd argument of f_open) */ 340 | #define FA_READ 0x01 341 | #define FA_WRITE 0x02 342 | #define FA_OPEN_EXISTING 0x00 343 | #define FA_CREATE_NEW 0x04 344 | #define FA_CREATE_ALWAYS 0x08 345 | #define FA_OPEN_ALWAYS 0x10 346 | #define FA_OPEN_APPEND 0x30 347 | 348 | /* Fast seek controls (2nd argument of f_lseek) */ 349 | #define CREATE_LINKMAP ((FSIZE_t)0 - 1) 350 | 351 | /* Format options (2nd argument of f_mkfs) */ 352 | #define FM_FAT 0x01 353 | #define FM_FAT32 0x02 354 | #define FM_EXFAT 0x04 355 | #define FM_ANY 0x07 356 | #define FM_SFD 0x08 357 | 358 | /* Filesystem type (FATFS.fs_type) */ 359 | #define FS_FAT12 1 360 | #define FS_FAT16 2 361 | #define FS_FAT32 3 362 | #define FS_EXFAT 4 363 | 364 | /* File attribute bits for directory entry (FILINFO.fattrib) */ 365 | #define AM_RDO 0x01 /* Read only */ 366 | #define AM_HID 0x02 /* Hidden */ 367 | #define AM_SYS 0x04 /* System */ 368 | #define AM_DIR 0x10 /* Directory */ 369 | #define AM_ARC 0x20 /* Archive */ 370 | 371 | 372 | #ifdef __cplusplus 373 | } 374 | #endif 375 | 376 | #endif /* FF_DEFINED */ 377 | -------------------------------------------------------------------------------- /ffconf.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / FatFs - Configuration file 3 | /---------------------------------------------------------------------------*/ 4 | 5 | #define FFCONF_DEF 63463 /* Revision ID */ 6 | 7 | /*---------------------------------------------------------------------------/ 8 | / Function Configurations 9 | /---------------------------------------------------------------------------*/ 10 | 11 | #define FF_FS_READONLY 0 12 | /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) 13 | / Read-only configuration removes writing API functions, f_write(), f_sync(), 14 | / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() 15 | / and optional writing functions as well. */ 16 | 17 | 18 | #define FF_FS_MINIMIZE 0 19 | /* This option defines minimization level to remove some basic API functions. 20 | / 21 | / 0: Basic functions are fully enabled. 22 | / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() 23 | / are removed. 24 | / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. 25 | / 3: f_lseek() function is removed in addition to 2. */ 26 | 27 | 28 | #define FF_USE_STRFUNC 1 29 | /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). 30 | / 31 | / 0: Disable string functions. 32 | / 1: Enable without LF-CRLF conversion. 33 | / 2: Enable with LF-CRLF conversion. */ 34 | 35 | 36 | #define FF_USE_FIND 0 37 | /* This option switches filtered directory read functions, f_findfirst() and 38 | / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ 39 | 40 | 41 | #define FF_USE_MKFS 0 42 | /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ 43 | 44 | 45 | #define FF_USE_FASTSEEK 0 46 | /* This option switches fast seek function. (0:Disable or 1:Enable) */ 47 | 48 | 49 | #define FF_USE_EXPAND 0 50 | /* This option switches f_expand function. (0:Disable or 1:Enable) */ 51 | 52 | 53 | #define FF_USE_CHMOD 0 54 | /* This option switches attribute manipulation functions, f_chmod() and f_utime(). 55 | / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ 56 | 57 | 58 | #define FF_USE_LABEL 0 59 | /* This option switches volume label functions, f_getlabel() and f_setlabel(). 60 | / (0:Disable or 1:Enable) */ 61 | 62 | 63 | #define FF_USE_FORWARD 0 64 | /* This option switches f_forward() function. (0:Disable or 1:Enable) */ 65 | 66 | 67 | /*---------------------------------------------------------------------------/ 68 | / Locale and Namespace Configurations 69 | /---------------------------------------------------------------------------*/ 70 | 71 | #define FF_CODE_PAGE 932 72 | /* This option specifies the OEM code page to be used on the target system. 73 | / Incorrect code page setting can cause a file open failure. 74 | / 75 | / 437 - U.S. 76 | / 720 - Arabic 77 | / 737 - Greek 78 | / 771 - KBL 79 | / 775 - Baltic 80 | / 850 - Latin 1 81 | / 852 - Latin 2 82 | / 855 - Cyrillic 83 | / 857 - Turkish 84 | / 860 - Portuguese 85 | / 861 - Icelandic 86 | / 862 - Hebrew 87 | / 863 - Canadian French 88 | / 864 - Arabic 89 | / 865 - Nordic 90 | / 866 - Russian 91 | / 869 - Greek 2 92 | / 932 - Japanese (DBCS) 93 | / 936 - Simplified Chinese (DBCS) 94 | / 949 - Korean (DBCS) 95 | / 950 - Traditional Chinese (DBCS) 96 | / 0 - Include all code pages above and configured by f_setcp() 97 | */ 98 | 99 | 100 | #define FF_USE_LFN 1 101 | #define FF_MAX_LFN 255 102 | /* The FF_USE_LFN switches the support for LFN (long file name). 103 | / 104 | / 0: Disable LFN. FF_MAX_LFN has no effect. 105 | / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. 106 | / 2: Enable LFN with dynamic working buffer on the STACK. 107 | / 3: Enable LFN with dynamic working buffer on the HEAP. 108 | / 109 | / To enable the LFN, ffunicode.c needs to be added to the project. The LFN function 110 | / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and 111 | / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. 112 | / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can 113 | / be in range of 12 to 255. It is recommended to be set 255 to fully support LFN 114 | / specification. 115 | / When use stack for the working buffer, take care on stack overflow. When use heap 116 | / memory for the working buffer, memory management functions, ff_memalloc() and 117 | / ff_memfree() in ffsystem.c, need to be added to the project. */ 118 | 119 | 120 | #define FF_LFN_UNICODE 0 121 | /* This option switches the character encoding on the API when LFN is enabled. 122 | / 123 | / 0: ANSI/OEM in current CP (TCHAR = char) 124 | / 1: Unicode in UTF-16 (TCHAR = WCHAR) 125 | / 2: Unicode in UTF-8 (TCHAR = char) 126 | / 3: Unicode in UTF-32 (TCHAR = DWORD) 127 | / 128 | / Also behavior of string I/O functions will be affected by this option. 129 | / When LFN is not enabled, this option has no effect. */ 130 | 131 | 132 | #define FF_LFN_BUF 255 133 | #define FF_SFN_BUF 12 134 | /* This set of options defines size of file name members in the FILINFO structure 135 | / which is used to read out directory items. These values should be suffcient for 136 | / the file names to read. The maximum possible length of the read file name depends 137 | / on character encoding. When LFN is not enabled, these options have no effect. */ 138 | 139 | 140 | #define FF_STRF_ENCODE 3 141 | /* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), 142 | / f_putc(), f_puts and f_printf() convert the character encoding in it. 143 | / This option selects assumption of character encoding ON THE FILE to be 144 | / read/written via those functions. 145 | / 146 | / 0: ANSI/OEM in current CP 147 | / 1: Unicode in UTF-16LE 148 | / 2: Unicode in UTF-16BE 149 | / 3: Unicode in UTF-8 150 | */ 151 | 152 | 153 | #define FF_FS_RPATH 0 154 | /* This option configures support for relative path. 155 | / 156 | / 0: Disable relative path and remove related functions. 157 | / 1: Enable relative path. f_chdir() and f_chdrive() are available. 158 | / 2: f_getcwd() function is available in addition to 1. 159 | */ 160 | 161 | 162 | /*---------------------------------------------------------------------------/ 163 | / Drive/Volume Configurations 164 | /---------------------------------------------------------------------------*/ 165 | 166 | #define FF_VOLUMES 2 167 | /* Number of volumes (logical drives) to be used. (1-10) */ 168 | 169 | 170 | #define FF_STR_VOLUME_ID 0 171 | #define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" 172 | /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. 173 | / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive 174 | / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each 175 | / logical drives. Number of items must not be less than FF_VOLUMES. Valid 176 | / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are 177 | / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is 178 | / not defined, a user defined volume string table needs to be defined as: 179 | / 180 | / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... 181 | */ 182 | 183 | 184 | #define FF_MULTI_PARTITION 0 185 | /* This option switches support for multiple volumes on the physical drive. 186 | / By default (0), each logical drive number is bound to the same physical drive 187 | / number and only an FAT volume found on the physical drive will be mounted. 188 | / When this function is enabled (1), each logical drive number can be bound to 189 | / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() 190 | / funciton will be available. */ 191 | 192 | 193 | #define FF_MIN_SS 512 194 | #define FF_MAX_SS 512 195 | /* This set of options configures the range of sector size to be supported. (512, 196 | / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and 197 | / harddisk. But a larger value may be required for on-board flash memory and some 198 | / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured 199 | / for variable sector size mode and disk_ioctl() function needs to implement 200 | / GET_SECTOR_SIZE command. */ 201 | 202 | 203 | #define FF_USE_TRIM 0 204 | /* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) 205 | / To enable Trim function, also CTRL_TRIM command should be implemented to the 206 | / disk_ioctl() function. */ 207 | 208 | 209 | #define FF_FS_NOFSINFO 0 210 | /* If you need to know correct free space on the FAT32 volume, set bit 0 of this 211 | / option, and f_getfree() function at first time after volume mount will force 212 | / a full FAT scan. Bit 1 controls the use of last allocated cluster number. 213 | / 214 | / bit0=0: Use free cluster count in the FSINFO if available. 215 | / bit0=1: Do not trust free cluster count in the FSINFO. 216 | / bit1=0: Use last allocated cluster number in the FSINFO if available. 217 | / bit1=1: Do not trust last allocated cluster number in the FSINFO. 218 | */ 219 | 220 | 221 | 222 | /*---------------------------------------------------------------------------/ 223 | / System Configurations 224 | /---------------------------------------------------------------------------*/ 225 | 226 | #define FF_FS_TINY 0 227 | /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) 228 | / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. 229 | / Instead of private sector buffer eliminated from the file object, common sector 230 | / buffer in the filesystem object (FATFS) is used for the file data transfer. */ 231 | 232 | 233 | #define FF_FS_EXFAT 0 234 | /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) 235 | / To enable exFAT, also LFN needs to be enabled. 236 | / Note that enabling exFAT discards ANSI C (C89) compatibility. */ 237 | 238 | 239 | #define FF_FS_NORTC 0 240 | #define FF_NORTC_MON 1 241 | #define FF_NORTC_MDAY 1 242 | #define FF_NORTC_YEAR 2018 243 | /* The option FF_FS_NORTC switches timestamp functiton. If the system does not have 244 | / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable 245 | / the timestamp function. Every object modified by FatFs will have a fixed timestamp 246 | / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. 247 | / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be 248 | / added to the project to read current time form real-time clock. FF_NORTC_MON, 249 | / FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. 250 | / These options have no effect at read-only configuration (FF_FS_READONLY = 1). */ 251 | 252 | 253 | #define FF_FS_LOCK 0 254 | /* The option FF_FS_LOCK switches file lock function to control duplicated file open 255 | / and illegal operation to open objects. This option must be 0 when FF_FS_READONLY 256 | / is 1. 257 | / 258 | / 0: Disable file lock function. To avoid volume corruption, application program 259 | / should avoid illegal open, remove and rename to the open objects. 260 | / >0: Enable file lock function. The value defines how many files/sub-directories 261 | / can be opened simultaneously under file lock control. Note that the file 262 | / lock control is independent of re-entrancy. */ 263 | 264 | 265 | #define FF_FS_REENTRANT 0 266 | #define FF_FS_TIMEOUT 1000 267 | #define FF_SYNC_t HANDLE 268 | /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs 269 | / module itself. Note that regardless of this option, file access to different 270 | / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() 271 | / and f_fdisk() function, are always not re-entrant. Only file/directory access 272 | / to the same volume is under control of this function. 273 | / 274 | / 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. 275 | / 1: Enable re-entrancy. Also user provided synchronization handlers, 276 | / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() 277 | / function, must be added to the project. Samples are available in 278 | / option/syscall.c. 279 | / 280 | / The FF_FS_TIMEOUT defines timeout period in unit of time tick. 281 | / The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, 282 | / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be 283 | / included somewhere in the scope of ff.h. */ 284 | 285 | /* #include // O/S definitions */ 286 | 287 | 288 | 289 | /*--- End of configuration options ---*/ 290 | -------------------------------------------------------------------------------- /integer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------*/ 2 | /* Integer type definitions for FatFs module */ 3 | /*-------------------------------------------*/ 4 | 5 | #ifndef _INTEGER 6 | #define _INTEGER 7 | 8 | #ifdef _WIN32 /* FatFs development platform */ 9 | 10 | #include 11 | #include 12 | 13 | #else /* Embedded platform */ 14 | 15 | /* These types must be 16-bit, 32-bit or larger integer */ 16 | typedef int INT; 17 | typedef unsigned int UINT; 18 | 19 | /* These types must be 8-bit integer */ 20 | typedef char CHAR; 21 | typedef unsigned char UCHAR; 22 | typedef unsigned char BYTE; 23 | 24 | /* These types must be 16-bit integer */ 25 | typedef short SHORT; 26 | typedef unsigned short USHORT; 27 | typedef unsigned short WORD; 28 | typedef unsigned short WCHAR; 29 | 30 | /* These types must be 32-bit integer */ 31 | typedef long LONG; 32 | typedef unsigned long ULONG; 33 | typedef unsigned long DWORD; 34 | 35 | #endif 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /interrupt.S: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | /* *********************************** */ 4 | /* REGISTERS */ 5 | reg_zero_s0 .req s0 6 | reg_one_s1 .req s1 7 | reg_gpioc_base_s2 .req s2 8 | reg_exti_base_s3 .req s3 9 | reg_combo_s4 .req s4 10 | reg_gpioa_base_s5 .req s5 11 | reg_swram_high_base_s6 .req s6 12 | reg_swram_low_base_s7 .req s7 13 | reg_dataout_moder_s8 .req s8 14 | reg_adcdata_s9 .req s9 15 | reg_save_r11_s30 .req s30 16 | 17 | 18 | 19 | /* MACROS */ 20 | 21 | .macro mov32, reg, val 22 | movw \reg, #:lower16:\val 23 | movt \reg, #:upper16:\val 24 | .endm 25 | 26 | .macro unrolled_exit_EXTI0 27 | //movs r1,#EXTI_Line0 28 | //str r1,[r10,IMR] 29 | 30 | //ldr r0,=EXTI0_tempvar 31 | //str r1,[r0] 32 | dsb 33 | #if defined(DEBUG_EXTI0_END) || defined(DEBUG_EXTI0_ROM_ACCESS) || defined(DEBUG_EXTI0_SWRAM_WRITE) 34 | //movs r0,#1 35 | vstr reg_one_s1,[r11,ODR] 36 | #endif 37 | #ifdef DEBUG_OUTPUT_ON_GPIOA 38 | vmov r11,reg_save_r11_s30 // pop r11 39 | #endif 40 | bx lr 41 | .endm 42 | 43 | .macro databus_write_delay 44 | .rept 10 45 | nop 46 | .endr 47 | .endm 48 | 49 | .macro databus_read_extra_delay 50 | .rept 8 51 | nop 52 | .endr 53 | .endm 54 | 55 | 56 | /* *********************************** */ 57 | .syntax unified 58 | .cpu cortex-m4 59 | // .fpu softvfp 60 | .fpu fpv4-sp-d16 61 | .thumb 62 | 63 | .global EXTI0_IRQHandler 64 | .global rom_base_start 65 | .global rom_base_end 66 | .global swram_low_base // swram 4,5,6,7 67 | .global swram_high_base // swram 12,13,14,15 68 | .global main_thread_command 69 | .global main_thread_data 70 | 71 | .global slot_4_base 72 | .global slot_5_base 73 | .global slot_6_base 74 | .global slot_7_base 75 | 76 | .global slot_12_base 77 | .global slot_13_base 78 | .global slot_14_base 79 | .global slot_15_base 80 | .global slots_end 81 | 82 | .section .rodata 83 | 84 | .include "roms-preloaded-from-flash.S" 85 | 86 | .section ccmram 87 | // swram_low_base consumes the entire 64K CCMRAM . Look in stm32_flash.ld for where the global symbol is defined 88 | // is defined in stm32_flash.ld 89 | //.lcomm swram_low_base,0x10000 // allocate 4 SWRAM slots ROM 4, 5, 6, 7 90 | 91 | .section bss 92 | .lcomm swram_high_base,0x10000 // allocate 4 SWRAM slots ROM 12,13,14,15 93 | // .lcomm EXTI0_tempvar,4 94 | 95 | .equ PERIPH_BB_BASE , 0x42000000 96 | 97 | .equ PERIPH_BASE , 0x40000000 98 | .equ PERIPH_BASE_APB1, (PERIPH_BASE + 0x00000) 99 | .equ PERIPH_BASE_APB2, (PERIPH_BASE + 0x10000) 100 | .equ PERIPH_BASE_AHB1, (PERIPH_BASE + 0x20000) 101 | .equ PERIPH_BASE_AHB2, 0x50000000 102 | .equ PERIPH_BASE_AHB3, 0x60000000 103 | 104 | .equ GPIOA_BASE, (PERIPH_BASE_AHB1 + 0x0000) 105 | .equ GPIOB_BASE, (PERIPH_BASE_AHB1 + 0x0400) 106 | .equ GPIOC_BASE, (PERIPH_BASE_AHB1 + 0x0800) 107 | .equ GPIOD_BASE, (PERIPH_BASE_AHB1 + 0x0C00) 108 | .equ GPIOE_BASE, (PERIPH_BASE_AHB1 + 0x1000) 109 | .equ GPIOF_BASE, (PERIPH_BASE_AHB1 + 0x1400) 110 | .equ GPIOG_BASE, (PERIPH_BASE_AHB1 + 0x1800) 111 | .equ GPIOH_BASE, (PERIPH_BASE_AHB1 + 0x1C00) 112 | .equ GPIOI_BASE, (PERIPH_BASE_AHB1 + 0x2000) 113 | 114 | .equ C_TO_D_OFFSET, (GPIOD_BASE - GPIOC_BASE) 115 | .equ C_TO_E_OFFSET, (GPIOE_BASE - GPIOC_BASE) 116 | 117 | .equ GPIOA_MODER , GPIOA_BASE + 0x00 118 | .equ GPIOA_OTYPER , GPIOA_BASE + 0x04 119 | .equ GPIOA_OSPEEDR , GPIOA_BASE + 0x08 120 | .equ GPIOA_PUPDR , GPIOA_BASE + 0x0C 121 | .equ GPIOA_IDR , GPIOA_BASE + 0x10 122 | .equ GPIOA_ODR , GPIOA_BASE + 0x14 123 | .equ GPIOA_BSRR , GPIOA_BASE + 0x18 124 | .equ GPIOA_LCKR , GPIOA_BASE + 0x1C 125 | .equ GPIOA_AFRL , GPIOA_BASE + 0x20 126 | .equ GPIOA_AFRH , GPIOA_BASE + 0x24 127 | 128 | .equ GPIOB_MODER , GPIOB_BASE + 0x00 129 | .equ GPIOB_OTYPER , GPIOB_BASE + 0x04 130 | .equ GPIOB_OSPEEDR , GPIOB_BASE + 0x08 131 | .equ GPIOB_PUPDR , GPIOB_BASE + 0x0C 132 | .equ GPIOB_IDR , GPIOB_BASE + 0x10 133 | .equ GPIOB_ODR , GPIOB_BASE + 0x14 134 | .equ GPIOB_BSRR , GPIOB_BASE + 0x18 135 | .equ GPIOB_LCKR , GPIOB_BASE + 0x1C 136 | .equ GPIOB_AFRL , GPIOB_BASE + 0x20 137 | .equ GPIOB_AFRH , GPIOB_BASE + 0x24 138 | 139 | .equ GPIOC_MODER , GPIOC_BASE + 0x00 140 | .equ GPIOC_OTYPER , GPIOC_BASE + 0x04 141 | .equ GPIOC_OSPEEDR , GPIOC_BASE + 0x08 142 | .equ GPIOC_PUPDR , GPIOC_BASE + 0x0C 143 | .equ GPIOC_IDR , GPIOC_BASE + 0x10 144 | .equ GPIOC_ODR , GPIOC_BASE + 0x14 145 | .equ GPIOC_BSRR , GPIOC_BASE + 0x18 146 | .equ GPIOC_LCKR , GPIOC_BASE + 0x1C 147 | .equ GPIOC_AFRL , GPIOC_BASE + 0x20 148 | .equ GPIOC_AFRH , GPIOC_BASE + 0x24 149 | 150 | .equ GPIOD_MODER , GPIOD_BASE + 0x00 151 | .equ GPIOD_OTYPER , GPIOD_BASE + 0x04 152 | .equ GPIOD_OSPEEDR , GPIOD_BASE + 0x08 153 | .equ GPIOD_PUPDR , GPIOD_BASE + 0x0C 154 | .equ GPIOD_IDR , GPIOD_BASE + 0x10 155 | .equ GPIOD_ODR , GPIOD_BASE + 0x14 156 | .equ GPIOD_BSRR , GPIOD_BASE + 0x18 157 | .equ GPIOD_LCKR , GPIOD_BASE + 0x1C 158 | .equ GPIOD_AFRL , GPIOD_BASE + 0x20 159 | .equ GPIOD_AFRH , GPIOD_BASE + 0x24 160 | 161 | .equ GPIOE_MODER , GPIOE_BASE + 0x00 162 | .equ GPIOE_OTYPER , GPIOE_BASE + 0x04 163 | .equ GPIOE_OSPEEDR , GPIOE_BASE + 0x08 164 | .equ GPIOE_PUPDR , GPIOE_BASE + 0x0C 165 | .equ GPIOE_IDR , GPIOE_BASE + 0x10 166 | .equ GPIOE_ODR , GPIOE_BASE + 0x14 167 | .equ GPIOE_BSRR , GPIOE_BASE + 0x18 168 | .equ GPIOE_LCKR , GPIOE_BASE + 0x1C 169 | .equ GPIOE_AFRL , GPIOE_BASE + 0x20 170 | .equ GPIOE_AFRH , GPIOE_BASE + 0x24 171 | 172 | .equ MODER , 0x00 173 | .equ OTYPER , 0x04 174 | .equ OSPEEDR , 0x08 175 | .equ IDR , 0x10 176 | .equ ODR , 0x14 177 | 178 | .equ ROMDIS_HIGH , 0x0008 179 | 180 | .equ SCB_AIRCR , 0xE000ED0C 181 | 182 | 183 | .equ EXTI_Line0 , 0x00001 184 | .equ EXTI_Line1 , 0x00002 185 | .equ EXTI_Line2 , 0x00004 186 | .equ EXTI_Line4 , 0x00010 187 | .equ EXTI , 0x40013c00 188 | .equ EXTI_IMR , EXTI + 0x00 189 | .equ EXTI_PR , EXTI + 0x14 190 | 191 | .equ IMR , 0x00 192 | .equ EMR , 0x04 193 | .equ RTSR , 0x08 194 | .equ FTSR , 0x0c 195 | .equ PR , 0x14 196 | 197 | .equ DSK_TRACKINFO_NUMBEROFSECTORS , 0x15 198 | .equ DSK_TRACKINFO_SECTORINFOLIST , 0x18 199 | 200 | 201 | .equ SYSCFG_BASE, 0x40013800 202 | .equ SYSCFG_EXTICR1, SYSCFG_BASE + 0x08 203 | 204 | 205 | 206 | // If straight GPIO 207 | //#define DATA_OUT_MODE 0x55550010 208 | //#define DATA_IN_MODE 0x00000010 209 | 210 | 211 | 212 | 213 | 214 | 215 | .section .data 216 | main_thread_command: 217 | .word 0x00000000 // command word 218 | main_thread_data: 219 | .word 0x00000000 // command arg 220 | 221 | .section .text 222 | 223 | // THETA0 Handler. Int on -ve edge 224 | 225 | .type EXTI0_IRQHandler, %function 226 | EXTI0_IRQHandler: 227 | // You need to at least add DEBUG_OUTPUT_ON_GPIOA in the Makefile to see debug output on PA0 228 | #ifdef DEBUG_OUTPUT_ON_GPIOA 229 | vmov reg_save_r11_s30,r11 // effectively s30 is our 'stack' 230 | vmov r11,reg_gpioa_base_s5 231 | #endif 232 | #ifdef DEBUG_EXTI0_START 233 | //movs r0,#0 234 | vstr reg_zero_s0,[r11,ODR] 235 | #endif 236 | 237 | vmov r12,reg_combo_s4 // r12 = combo bits 238 | //lsrs r0,r12,#16 // Move top half word of r12 into lower half of r0 239 | //movt r0,#0x5555 // So should be 55550020 in SDIO mode, 55550010 in GPIO mode 240 | //vmov reg_dataout_moder_s7,r0 241 | 242 | vmov r3,reg_exti_base_s3 // r3 = EXTI 243 | vstr reg_one_s1,[r3,PR] // clear interrupt 244 | 245 | //ldr r0,=swram_high_base 246 | //vmov s6,r0 // should be able to compute this from main thread 247 | 248 | vmov r2,reg_gpioc_base_s2 249 | wait_for_phi0_high: 250 | movs r3,#1 251 | 2: ldr r0,[r2, C_TO_E_OFFSET+IDR] 252 | ldr r1,[r2,IDR] 253 | tst r1,r3 254 | beq 2b 255 | 256 | phi0_high: 257 | lsls r3,r0,#17 // A15 -> C 258 | bcs upper_32k 259 | 260 | // We fall through to the exit here because when we get the chance to exit the ISR we really really want to exit quickly to give time back to the main thread 261 | exit_EXTI0: 262 | unrolled_exit_EXTI0 263 | 264 | 265 | upper_32k: 266 | bmi process_registers // A15 = 1 and A14 = 1 267 | 268 | lsls r3,r12,#29 // b3 -> Carry, b2 -> pl/mi 269 | bpl exit_EXTI0 // ROMS 0,1,2,3 and 8,9,10,11 270 | // should be ROM 4,5,6,7 or 12,13,14,15 271 | ITE CC 272 | vmovcc r3,reg_swram_low_base_s7 273 | vmovcs r3,reg_swram_high_base_s6 274 | 275 | bfi r0,r12,#14,#2 276 | tst r1,#0x0002 277 | beq write_sideways_ram // should be to write to sideways ram 278 | #ifdef DEBUG_EXTI0_ROM_ACCESS 279 | vstr reg_zero_s0,[r11,ODR] 280 | #endif 281 | 282 | // r1 should have port c in it, so upper 16 bits should be zero 283 | lsrs r1,r12,#8 // Move pd2 bits into bottom 8 bits 284 | ldrb r3,[r3,r0] // get byte from rom in lower 8 bits 285 | bfi r1,r3,#8,#8 //Copy bottom 8 bits of r3 into b15-b8 of r1 286 | 287 | vmov r0,reg_dataout_moder_s8 288 | str r1,[r2, C_TO_D_OFFSET + ODR] // GPIOD ODR 289 | str r0,[r2, C_TO_D_OFFSET + MODER] // MODER set to outputs 290 | 291 | //movs r1,#1 292 | vmov r3,reg_exti_base_s3 293 | vstr reg_one_s1,[r3,EMR] // EXTI_EMR - wait for an event rather than an interrupt on PC0 294 | 295 | 296 | lsrs r1,r12,#16 // Move top half word of r12 into lower half of r1, and also leave top 16 bits as zero (ie. Data IN mode) 297 | 298 | dsb 299 | sev // set the event register 300 | wfe // clear the event register 301 | // So the 2nd wfe is meant to wait for the -ve edge, but if you get a spurious edge at exactly the time these instructions execute, it can slip through without waiting 302 | wfe // wait for -ve edge of phi0 303 | 304 | databus_read_extra_delay 305 | 306 | str r1,[r2, C_TO_D_OFFSET + MODER] // MODER set to inputs 307 | 308 | #ifdef DEBUG_EXTI0_ROM_ACCESS 309 | vstr reg_one_s1,[r11,ODR] 310 | vstr reg_zero_s0,[r11,ODR] 311 | #endif 312 | 313 | b wait_for_phi0_high 314 | 315 | 316 | write_sideways_ram: 317 | #ifdef DEBUG_EXTI0_SWRAM_WRITE 318 | vstr reg_zero_s0,[r11,ODR] 319 | #endif 320 | databus_write_delay 321 | 322 | ldr r1,[r2,C_TO_D_OFFSET+IDR] // GPIOD read databus 323 | lsrs r1,r1,#8 324 | strb r1,[r3,r0] 325 | 326 | unrolled_exit_EXTI0 327 | //b wait_for_phi0_high // We should probably exit here, as phi0 is probably already high 328 | 329 | 330 | 331 | // tbh only makes FORWARD jumps 332 | process_registers: 333 | subs r0,r0,#0xfc00 334 | bmi exit_EXTI0 // jump away if its between c000 and fbff 335 | // the TBH does a jump table based on possible 'IO register addresses from external computer'. Each entry is 2 bytes, and will 336 | // usually jump to register_unused. But change entries for the registers you want to emulate (eg. FE05 is the sideways ROM register 337 | // in an Electron 338 | tbh.w [pc,r0,lsl #1] 339 | .include "electron_branchtable.S" 340 | 341 | 342 | 343 | register_unused: 344 | unrolled_exit_EXTI0 345 | 346 | // Handle registers we are interested in 347 | register_0xfe05: 348 | #ifdef DEBUG_FE05 349 | vstr reg_zero_s0,[r11, ODR] 350 | #endif 351 | tst r1,#0x0002 // see if r/w is low 352 | bne exit_EXTI0 353 | databus_write_delay 354 | ldr r0,[r2,C_TO_D_OFFSET+IDR] // GPIOD IDR 355 | lsrs r0,r0,#8 356 | bfi r12,r0,#0,#4 // copy lowest 4 bits of r0 into r12 lowest 4 bits 357 | vmov reg_combo_s4,r12 358 | 359 | #ifdef DEBUG_FE05 360 | vstr s1,[r11, ODR] 361 | #endif 362 | unrolled_exit_EXTI0 363 | 364 | // ROM swap control ports 365 | register_0xfc04: 366 | register_0xfc05: 367 | register_0xfc06: 368 | register_0xfc07: 369 | register_0xfc0c: 370 | register_0xfc0d: 371 | register_0xfc0e: 372 | register_0xfc0f: 373 | ands r3,r0,#0x0f // get rom number based on the address bus 374 | tst r1,#0x0002 // see if r/w is low 375 | bne exit_EXTI0 376 | 377 | databus_write_delay 378 | 379 | ldr r0,[r2,C_TO_D_OFFSET+IDR] // GPIOD IDR 380 | lsrs r0,r0,#8 // r0 has rom to swap to 381 | bfi r0,r3,#8,#4 // copy lowest 4 bits of r3 into r0 b11-b8 382 | // r0 should have b29 set, then b11-b8 with the rom slot and b7-b0 as the rom number on the SD card. ie a file in roms/ 383 | orr r0,#MAIN_THREAD_ROM_SWAP_COMMAND 384 | ldr r1,=main_thread_command 385 | str r0,[r1] // write the main thread command 386 | unrolled_exit_EXTI0 387 | 388 | 389 | register_0xfc70: 390 | #ifdef DEBUG_FC70 391 | vstr s1,[r11,ODR] // set PA0 high 392 | #endif 393 | tst r1,#0x0002 // see if r/w is low 394 | beq write_register_0xfc70 395 | // Must be a read of 0xfc70 396 | vmov r1,reg_adcdata_s9 397 | orr r1,#0x8000000 398 | vmov reg_adcdata_s9,r1 399 | lsls r1,r1,#8 // bottom 8 bits of r1 into b15-8 400 | 401 | lsrs r0,r12,#8 // get PD2 state into lower 8 bits 402 | bfi r1,r0,#0,#8 //Copy bottom 8 bits of r0 into b7-b0 of r1 403 | vmov r0,reg_dataout_moder_s8 404 | str r1,[r2,C_TO_D_OFFSET+ODR] // GPIOD ODR 405 | str r0,[r2, C_TO_D_OFFSET+MODER] // MODER set to outputs 406 | 407 | vmov r3,reg_exti_base_s3 408 | vstr reg_one_s1,[r3,EMR] // EXTI_EMR - wait for an event rather than an interrupt on PC0 409 | 410 | lsrs r1,r12,#16 // Move top half word of r8 into lower half of r1 411 | 412 | dsb 413 | sev // set the event register 414 | wfe // clear the event register 415 | wfe // wait for negative edge 416 | 417 | databus_read_extra_delay 418 | 419 | str r1,[r2, C_TO_D_OFFSET + MODER] // MODER set to inputs 420 | unrolled_exit_EXTI0 421 | write_register_0xfc70: 422 | databus_write_delay 423 | ldr r0,[r2,C_TO_D_OFFSET+IDR] // GPIOD IDR 424 | tst r0,#0x0400 // b2 of databus. Must be high to initiate an ADC conversion 425 | beq exit_EXTI0 426 | cmp r0,#0x400 427 | blt exit_EXTI0 428 | cmp r0,#0x800 429 | bge exit_EXTI0 430 | vmov r1,reg_adcdata_s9 431 | lsls r3,r1,#1 // b31 into Carry 432 | bcs exit_EXTI0 // exit if another conversion in progress 433 | orr r1, #0x80000000 //set b31 high to indicate that the result is not ready 434 | 435 | lsrs r0,r0,#8 // move databus value into lower 8 bits 436 | 437 | ands r0,#3 // value should to 0 to 3 for ADC channels 0 to 3 438 | bfi r1,r0,#0,#2 // copy lowest two bits of r0 (the adc channel) into bits 1 and 0 of r1 439 | vmov reg_adcdata_s9,r1 // s9 should be b31=1 and bits 1 and 0 with ADC channel 440 | 441 | orr r0,#MAIN_THREAD_REQUEST_ADC_CONVERSION_COMMAND 442 | ldr r1,=main_thread_command 443 | str r0,[r1] // write the main thread command 444 | 445 | #ifdef DEBUG_FC70 446 | vstr reg_zero_s0,[r11,ODR] // set PA0 HIGH 447 | #endif 448 | 449 | unrolled_exit_EXTI0 450 | 451 | // FC71 is the Electron Plus 1 printer out port 452 | register_0xfc71: 453 | tst r1,#0x0002 // see if r/w is low 454 | bne exit_EXTI0 455 | #ifdef DEBUG_FC71 456 | vstr s1,[r11,ODR] // set PA0 high 457 | #endif 458 | // MOSI is D0, SCK is D1 from the Electrons perspective. These come in on D8 and D9 for us. 459 | // MOSI needs to go out as PD2. SCK goes out as PC12 and we need to keep PC11 low for CS/ 460 | movs r3,#0 461 | databus_write_delay 462 | ldr r0,[r2,C_TO_D_OFFSET+IDR] // GPIOD IDR 463 | tst r0,#0x0100 // PD8 464 | ITE NE 465 | orrne r12,#0x0400 // PD2 but shifted to the left by 8 466 | bfceq r12,#10,#1 467 | lsrs r1,r12,#8 468 | str r1,[r2,C_TO_D_OFFSET+ODR] 469 | vmov s4,r12 470 | 471 | movs r1,#0 472 | tst r0,#0x0200 // test PD9 473 | IT NE 474 | orrne r1,#0x1000 475 | str r1,[r2,ODR] // GPIOC ODR 476 | 477 | 478 | #ifdef DEBUG_FC71 479 | vstr reg_zero_s0,[r11,ODR] // set PA0 HIGH 480 | #endif 481 | 482 | unrolled_exit_EXTI0 483 | 484 | 485 | register_0xfc72: 486 | // First check if this is a READ 487 | tst r1,#0x0002 // see if r/w is low 488 | beq exit_EXTI0 489 | #ifdef DEBUG_FC72 490 | vstr reg_one_s1,[r11,ODR] 491 | #endif 492 | // D7 is ACK from the electrons perspective, but D15 to us. It is PC8 493 | //ldr r6,[reg_gpioc_base,#0x10] // GPIOC IDR 494 | // r1 is a read of port C which will have PC11 and PC12 and PC8. We only need PC8 495 | lsrs r3,r1,#2 // PC3 and PC2 shifted into bits 1 and 0 of r3 (fire buttons on joystick) 496 | ands r1,r1,#0x0100 497 | lsls r1,r1,#7 // PC8 gets shifted into b15 so that it will end up as b7 to the 6502 498 | lsrs r0,r12,#8 // get PD2 state into lower 8 bits 499 | bfi r1,r0,#0,#8 // copy lowest 8 bits of r0 into lowest 8 bits of r1. Adds PD2 state in 500 | bfi r1,r3,#12,#2 // lowest two bits of r3 (fire buttons) shifted in to b13 (b5 on 650) and b12 (b4 on 6502) 501 | vmov r0,reg_dataout_moder_s8 502 | vmov r3,reg_adcdata_s9 503 | lsls r3,r3,#1 // shift bit 31 into Carry 504 | ITE CC 505 | bfccc r1,#14,#1 // clear bit 14 (b6 on data bus) to say ADC conversion is complete 506 | orrcs r1,#0x4000 // set bit 14 (b6 on data bus) to say ADC conversion is not complete 507 | 508 | str r1,[r2,C_TO_D_OFFSET+ODR] // GPIOD ODR 509 | str r0,[r2, C_TO_D_OFFSET+MODER] // MODER set to outputs 510 | //movs r1,#1 511 | vmov r3,reg_exti_base_s3 512 | vstr reg_one_s1,[r3,EMR] // EXTI_EMR - wait for an event rather than an interrupt on PC0 513 | 514 | //movs r0,#1 515 | 516 | //movs r1,#DATA_IN_MODE 517 | lsrs r1,r12,#16 // Move top half word of r8 into lower half of r1 518 | //movt r1,#0 // Again not entirely necessary 519 | 520 | dsb 521 | sev // set the event register 522 | wfe // clear the event register 523 | wfe // wait for negative edge 524 | 525 | //databus_read_extra_delay 526 | 527 | str r1,[r2, C_TO_D_OFFSET + MODER] // MODER set to inputs 528 | 529 | 530 | unrolled_exit_EXTI0 531 | 532 | 533 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "main.h" 4 | #include "stm32f4xx.h" 5 | 6 | #include "ff.h" 7 | #include "diskio.h" 8 | 9 | 10 | 11 | GPIO_InitTypeDef GPIO_InitStructure; 12 | 13 | 14 | 15 | // Must be volatile to prevent optimiser doing stuff 16 | extern volatile uint32_t main_thread_command; 17 | extern volatile uint32_t main_thread_data; 18 | extern volatile uint8_t *rom_base_start; 19 | extern volatile uint8_t *rom_base_end; 20 | extern volatile uint8_t *swram_low_base; 21 | extern volatile uint8_t *swram_high_base; 22 | 23 | extern volatile uint8_t *slot_4_base; 24 | extern volatile uint8_t *slot_5_base; 25 | extern volatile uint8_t *slot_6_base; 26 | extern volatile uint8_t *slot_7_base; 27 | extern volatile uint8_t *slot_12_base; 28 | extern volatile uint8_t *slot_13_base; 29 | extern volatile uint8_t *slot_14_base; 30 | extern volatile uint8_t *slot_15_base; 31 | extern volatile uint8_t *slots_end; 32 | 33 | #ifdef ENABLE_SEMIHOSTING 34 | extern void initialise_monitor_handles(void); /*rtt*/ 35 | #endif 36 | 37 | FATFS fs32; 38 | char temp_rom[16384]; 39 | 40 | 41 | 42 | #if _USE_LFN 43 | static char lfn[_MAX_LFN + 1]; 44 | fno.lfname = lfn; 45 | fno.lfsize = sizeof lfn; 46 | #endif 47 | 48 | // Enable the FPU (Cortex-M4 - STM32F4xx and higher) 49 | // http://infocenter.arm.com/help/topic/com.arm.doc.dui0553a/BEHBJHIG.html 50 | // Also make sure lazy stacking is disabled 51 | void enable_fpu_and_disable_lazy_stacking() { 52 | __asm volatile 53 | ( 54 | " ldr.w r0, =0xE000ED88 \n" /* The FPU enable bits are in the CPACR. */ 55 | " ldr r1, [r0] \n" /* read CAPCR */ 56 | " orr r1, r1, #( 0xf << 20 )\n" /* Set bits 20-23 to enable CP10 and CP11 coprocessors */ 57 | " str r1, [r0] \n" /* Write back the modified value to the CPACR */ 58 | " dsb \n" /* wait for store to complete */ 59 | " isb \n" /* reset pipeline now the FPU is enabled */ 60 | // Disable lazy stacking (the default) and effectively have no stacking since we're not really using the FPU for anything other than a fast register store 61 | " ldr.w r0, =0xE000EF34 \n" /* The FPU FPCCR. */ 62 | " ldr r1, [r0] \n" /* read FPCCR */ 63 | " bfc r1, #30,#2\n" /* Clear bits 30-31. ASPEN and LSPEN. This disables lazy stacking */ 64 | " str r1, [r0] \n" /* Write back the modified value to the FPCCR */ 65 | " dsb \n" /* wait for store to complete */ 66 | " isb" /* reset pipeline */ 67 | :::"r0","r1" 68 | ); 69 | } 70 | 71 | // From some reddit thread on fast itoa 72 | static const char itoa_lookup[][4] = {"\x00\x00\x00\x01", "\x00\x00\x00\x02", "\x00\x00\x00\x04", 73 | "\x00\x00\x00\x08", "\x00\x00\x01\x06", "\x00\x00\x03\x02", "\x00\x00\x06\x04", 74 | "\x00\x01\x02\x08", "\x00\x02\x05\x06", "\x00\x05\x01\x02"}; 75 | 76 | 77 | void itoa_base10(int val, char *dest) 78 | { 79 | int bitnum, dignum; 80 | char sum, carry, result[4] = "\x00\x00\x00\x00"; 81 | const char *lookup; 82 | 83 | for(bitnum = 0; bitnum < 10; ++bitnum) { 84 | if(val & (1 << bitnum)) { 85 | carry = 0; 86 | lookup = itoa_lookup[bitnum]; 87 | for(dignum = 3; dignum >= 0; --dignum) { 88 | sum = result[dignum] + lookup[dignum] + carry; 89 | if(sum < 10) { 90 | carry = 0; 91 | } else { 92 | carry = 1; 93 | sum -= 10; 94 | } 95 | result[dignum] = sum; 96 | } 97 | } 98 | } 99 | for(dignum = 0; !result[dignum] && dignum < 3; ++dignum) 100 | ; 101 | 102 | for(; dignum < 4; ++dignum) { 103 | *dest++ = result[dignum] + '0'; 104 | } 105 | *dest++ = 0; 106 | } 107 | 108 | void delay_ms(const uint16_t ms) 109 | { 110 | uint32_t i = ms * 27778; 111 | while (i-- > 0) { 112 | __asm volatile ("nop"); 113 | } 114 | } 115 | 116 | void my_memcpy(unsigned char *dest, unsigned char *from, unsigned char *to) { 117 | unsigned char *q = dest; 118 | unsigned char *p = from; 119 | 120 | while (p 0) { 131 | my_memcpy(swram,(unsigned char *)&slot_4_base,(unsigned char *)&slot_5_base); 132 | } 133 | swram+=16384; 134 | if ((&slot_6_base - &slot_5_base)> 0) { 135 | my_memcpy(swram,(unsigned char *)&slot_5_base,(unsigned char *)&slot_6_base); 136 | } 137 | swram+=16384; 138 | if ((&slot_7_base - &slot_6_base)> 0) { 139 | my_memcpy(swram,(unsigned char *)&slot_6_base,(unsigned char *)&slot_7_base); 140 | } 141 | swram+=16384; 142 | if ((&slot_12_base - &slot_7_base)> 0) { 143 | my_memcpy(swram,(unsigned char *)&slot_7_base,(unsigned char *)&slot_12_base); 144 | } 145 | 146 | 147 | swram = (unsigned char *) &swram_high_base; 148 | 149 | if ((&slot_13_base - &slot_12_base)> 0) { 150 | my_memcpy(swram,(unsigned char *)&slot_12_base,(unsigned char *)&slot_13_base); 151 | } 152 | swram+=16384; 153 | if ((&slot_14_base - &slot_13_base)> 0) { 154 | my_memcpy(swram,(unsigned char *)&slot_13_base,(unsigned char *)&slot_14_base); 155 | } 156 | swram+=16384; 157 | if ((&slot_15_base - &slot_14_base)> 0) { 158 | my_memcpy(swram,(unsigned char *)&slot_14_base,(unsigned char *)&slot_15_base); 159 | } 160 | swram+=16384; 161 | if ((&slots_end - &slot_15_base)> 0) { 162 | my_memcpy(swram,(unsigned char *)&slot_15_base,(unsigned char *)&slots_end); 163 | } 164 | 165 | } 166 | 167 | 168 | 169 | 170 | 171 | enum sysclk_freq { 172 | SYSCLK_42_MHZ=0, 173 | SYSCLK_84_MHZ, 174 | SYSCLK_168_MHZ, 175 | SYSCLK_200_MHZ, 176 | SYSCLK_240_MHZ, 177 | }; 178 | 179 | void rcc_set_frequency(enum sysclk_freq freq) 180 | { 181 | int freqs[] = {42, 84, 168, 200, 240}; 182 | 183 | /* USB freqs: 42MHz, 42Mhz, 48MHz, 50MHz, 48MHz */ 184 | int pll_div[] = {2, 4, 7, 10, 10}; 185 | 186 | /* PLL_VCO = (HSE_VALUE / PLL_M) * PLL_N */ 187 | /* SYSCLK = PLL_VCO / PLL_P */ 188 | /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ 189 | uint32_t PLL_P = 2; 190 | uint32_t PLL_N = freqs[freq] * 2; 191 | uint32_t PLL_M = (HSE_VALUE/1000000); 192 | uint32_t PLL_Q = pll_div[freq]; 193 | 194 | RCC_DeInit(); 195 | 196 | /* Enable HSE osscilator */ 197 | RCC_HSEConfig(RCC_HSE_ON); 198 | 199 | if (RCC_WaitForHSEStartUp() == ERROR) { 200 | return; 201 | } 202 | 203 | /* Configure PLL clock M, N, P, and Q dividers */ 204 | RCC_PLLConfig(RCC_PLLSource_HSE, PLL_M, PLL_N, PLL_P, PLL_Q); 205 | 206 | /* Enable PLL clock */ 207 | RCC_PLLCmd(ENABLE); 208 | 209 | /* Wait until PLL clock is stable */ 210 | while ((RCC->CR & RCC_CR_PLLRDY) == 0); 211 | 212 | /* Set PLL_CLK as system clock source SYSCLK */ 213 | RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); 214 | 215 | /* Set AHB clock divider */ 216 | RCC_HCLKConfig(RCC_SYSCLK_Div1); 217 | 218 | //FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; 219 | FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; 220 | 221 | /* Set APBx clock dividers */ 222 | switch (freq) { 223 | /* Max freq APB1: 42MHz APB2: 84MHz */ 224 | case SYSCLK_42_MHZ: 225 | RCC_PCLK1Config(RCC_HCLK_Div1); /* 42MHz */ 226 | RCC_PCLK2Config(RCC_HCLK_Div1); /* 42MHz */ 227 | break; 228 | case SYSCLK_84_MHZ: 229 | RCC_PCLK1Config(RCC_HCLK_Div2); /* 42MHz */ 230 | RCC_PCLK2Config(RCC_HCLK_Div1); /* 84MHz */ 231 | break; 232 | case SYSCLK_168_MHZ: 233 | RCC_PCLK1Config(RCC_HCLK_Div4); /* 42MHz */ 234 | RCC_PCLK2Config(RCC_HCLK_Div2); /* 84MHz */ 235 | break; 236 | case SYSCLK_200_MHZ: 237 | RCC_PCLK1Config(RCC_HCLK_Div4); /* 50MHz */ 238 | RCC_PCLK2Config(RCC_HCLK_Div2); /* 100MHz */ 239 | break; 240 | case SYSCLK_240_MHZ: 241 | RCC_PCLK1Config(RCC_HCLK_Div4); /* 60MHz */ 242 | RCC_PCLK2Config(RCC_HCLK_Div2); /* 120MHz */ 243 | break; 244 | } 245 | 246 | /* Update SystemCoreClock variable */ 247 | SystemCoreClockUpdate(); 248 | } 249 | 250 | //void SD_NVIC_Configuration(FunctionalState state) 251 | //{ 252 | // NVIC_InitTypeDef NVIC_InitStructure; 253 | // 254 | // /* Configure the NVIC Preemption Priority Bits */ 255 | // //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 256 | // //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); 257 | // 258 | // NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn; 259 | // //NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 260 | // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // This must be a lower priority (ie. higher number) than the phi0 int 261 | // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 262 | // NVIC_InitStructure.NVIC_IRQChannelCmd = state; 263 | // NVIC_Init(&NVIC_InitStructure); 264 | //} 265 | // 266 | // 267 | // 268 | //void SDIO_IRQHandler(void) 269 | //{ 270 | // /* Process All SDIO Interrupt Sources */ 271 | // SD_ProcessIRQSrc(); 272 | //} 273 | 274 | // _IORQ interrupt 275 | void config_PC0_int(void) { 276 | EXTI_InitTypeDef EXTI_InitStruct; 277 | NVIC_InitTypeDef NVIC_InitStruct; 278 | 279 | /* Enable clock for SYSCFG */ 280 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); 281 | 282 | SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource0); 283 | 284 | EXTI_InitStruct.EXTI_Line = EXTI_Line0; 285 | /* Enable interrupt */ 286 | EXTI_InitStruct.EXTI_LineCmd = ENABLE; 287 | /* Interrupt mode */ 288 | EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; 289 | /* Triggers on rising and falling edge */ 290 | //EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; 291 | EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; 292 | /* Add to EXTI */ 293 | EXTI_Init(&EXTI_InitStruct); 294 | 295 | /* Add IRQ vector to NVIC */ 296 | /* PC0 is connected to EXTI_Line0, which has EXTI0_IRQn vector */ 297 | NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; 298 | /* Set priority */ 299 | NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00; 300 | /* Set sub priority */ 301 | NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00; 302 | /* Enable interrupt */ 303 | NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; 304 | /* Add to NVIC */ 305 | NVIC_Init(&NVIC_InitStruct); 306 | } 307 | 308 | 309 | 310 | 311 | /* SD card uses PC10, PC11, PC12 out and PC8 in */ 312 | void config_gpio_portc(void) { 313 | GPIO_InitTypeDef GPIO_InitStructure; 314 | /* GPIOC Periph clock enable */ 315 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); 316 | 317 | /* Configure GPIO Settings */ 318 | // non SDIO 319 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12; 320 | 321 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 322 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 323 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 324 | #ifdef DISABLE_PULLUPS_FOR_SDCARD 325 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 326 | #else 327 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 328 | #endif 329 | GPIO_Init(GPIOC, &GPIO_InitStructure); 330 | 331 | // Also SD Card (so will inherit the pullup/nopull setting above 332 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; 333 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; 334 | GPIO_Init(GPIOC, &GPIO_InitStructure); 335 | 336 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; 337 | //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 ; 338 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 339 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; 340 | GPIO_Init(GPIOC, &GPIO_InitStructure); 341 | 342 | GPIOC->ODR = 0xFFFF; 343 | } 344 | 345 | /* Input/Output data GPIO pins on PD{8..15}. Also PD2 is used fo MOSI on the STM32F407VET6 board I have */ 346 | void config_gpio_data(void) { 347 | GPIO_InitTypeDef GPIO_InitStructure; 348 | /* GPIOD Periph clock enable */ 349 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); 350 | 351 | /* Configure GPIO Settings */ 352 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | 353 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; 354 | 355 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; 356 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 357 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 358 | //GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 359 | //GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; 360 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 361 | GPIO_Init(GPIOD, &GPIO_InitStructure); 362 | 363 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ; 364 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 365 | #ifdef DISABLE_PULLUPS_FOR_SDCARD 366 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 367 | #else 368 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 369 | #endif 370 | GPIO_Init(GPIOD, &GPIO_InitStructure); 371 | } 372 | 373 | /* Input Address GPIO pins on PE{0..15} */ 374 | void config_gpio_addr(void) { 375 | GPIO_InitTypeDef GPIO_InitStructure; 376 | /* GPIOE Periph clock enable */ 377 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); 378 | 379 | /* Configure GPIO Settings */ 380 | GPIO_InitStructure.GPIO_Pin = 381 | GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | 382 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | 383 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | 384 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; 385 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; 386 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 387 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 388 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; 389 | GPIO_Init(GPIOE, &GPIO_InitStructure); 390 | } 391 | 392 | /* Debug GPIO pins on PA0 */ 393 | void config_gpio_dbg(void) { 394 | GPIO_InitTypeDef GPIO_InitStructure; 395 | /* GPIOA Periph clock enable */ 396 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 397 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,DISABLE); 398 | 399 | 400 | /* Configure GPIO Settings */ 401 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; 402 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 403 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 404 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 405 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 406 | GPIO_Init(GPIOA, &GPIO_InitStructure); 407 | } 408 | 409 | void ADC_Config(void) 410 | { 411 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 412 | // Enable clock for ADC1 413 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 414 | // Init GPIOA for ADC input 415 | GPIO_InitTypeDef GPIO_InitStruct; 416 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN; 417 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5; 418 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; 419 | GPIO_Init(GPIOA, &GPIO_InitStruct); 420 | 421 | // Init ADC1 422 | ADC_InitTypeDef ADC_InitStruct; 423 | ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; 424 | ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; 425 | ADC_InitStruct.ADC_ExternalTrigConv = DISABLE; 426 | ADC_InitStruct.ADC_ExternalTrigConvEdge = 427 | ADC_ExternalTrigConvEdge_None; 428 | ADC_InitStruct.ADC_NbrOfConversion = 1; 429 | ADC_InitStruct.ADC_Resolution = ADC_Resolution_8b; 430 | ADC_InitStruct.ADC_ScanConvMode = DISABLE; 431 | ADC_Init(ADC1, &ADC_InitStruct); 432 | ADC_Cmd(ADC1, ENABLE); 433 | 434 | 435 | } 436 | 437 | uint16_t ADC_Read(int channel) 438 | { 439 | uint16_t v; 440 | switch(channel) { 441 | case (0): 442 | ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_84Cycles); 443 | break; 444 | case (1): 445 | ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 1, ADC_SampleTime_84Cycles); 446 | break; 447 | default: 448 | return 0; 449 | } 450 | // Start ADC conversion 451 | ADC_SoftwareStartConv(ADC1); 452 | // Wait until conversion is finish 453 | while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); 454 | 455 | v = ADC_GetConversionValue(ADC1); 456 | return v; 457 | } 458 | 459 | 460 | void config_backup_sram(void) { 461 | 462 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); 463 | PWR_BackupAccessCmd(ENABLE); 464 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE); 465 | PWR_BackupRegulatorCmd(ENABLE); 466 | } 467 | 468 | void scan_and_load_roms() { 469 | FRESULT res; 470 | FIL fil; 471 | TCHAR root_directory[11] = "/boot/"; 472 | 473 | TCHAR full_filename[64]; 474 | DIR dir; 475 | static FILINFO fno; 476 | UINT BytesRead; 477 | char *swram; 478 | int rom_offset; 479 | int root_directory_base_length= strlen(root_directory); 480 | 481 | for (int highlow = 0;highlow <= 1 ; highlow++) { 482 | if (highlow==0) { 483 | swram = (char *) &swram_high_base; 484 | } else { 485 | swram = (char *) &swram_low_base; 486 | } 487 | for (int i = 0; i<=3 ; i++) { 488 | if (highlow==0) { 489 | rom_offset=12; 490 | } else { 491 | rom_offset=4; 492 | } 493 | itoa_base10(i+rom_offset, &root_directory[root_directory_base_length]); 494 | #ifdef SEMIHOSTING_SDCARD 495 | printf("about to open %s\n",root_directory); 496 | #endif 497 | res = f_opendir(&dir, root_directory); 498 | if (res == FR_OK) { 499 | #ifdef SEMIHOSTING_SDCARD 500 | printf("dir open\n"); 501 | #endif 502 | for (;;) { 503 | res = f_readdir(&dir, &fno); /* Read a directory item */ 504 | if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */ 505 | strcpy(full_filename,root_directory); 506 | strcat(full_filename,"/"); 507 | strcat(full_filename,fno.fname); 508 | res = f_open(&fil, full_filename, FA_READ); 509 | if (res == FR_OK) { 510 | #ifdef SEMIHOSTING_SDCARD 511 | printf("%d,%d: opened %s 0x%08x\n",highlow,i,full_filename, swram); 512 | #endif 513 | if (highlow==0) { 514 | res = f_read(&fil, swram, 16384, &BytesRead); 515 | } else { 516 | // The f_read will never write directly to CCMRAM 517 | res = f_read(&fil, temp_rom, 16384, &BytesRead); 518 | memcpy(swram,temp_rom,16384); 519 | } 520 | f_close(&fil); 521 | } 522 | break; // only interested in the first file in the dir 523 | } 524 | f_closedir(&dir); 525 | } 526 | swram+=0x4000; 527 | } 528 | } 529 | } 530 | 531 | 532 | void load_rom(uint8_t slot, uint8_t rom_number_on_sdcard) { 533 | FRESULT res; 534 | FIL fil; 535 | TCHAR root_directory[18] = "/roms/"; 536 | TCHAR full_filename[64]; 537 | DIR dir; 538 | static FILINFO fno; 539 | UINT BytesRead; 540 | char *swram; 541 | int root_directory_base_length = strlen(root_directory); 542 | int highslot; 543 | 544 | 545 | 546 | 547 | 548 | // only handle slots 4 to 7 and 12 to 15 549 | if (slot >=12 && slot <=15) { 550 | swram = (char *) &swram_high_base; 551 | highslot=1; 552 | } else if (slot >=4 && slot <=7) { 553 | swram = (char *) &swram_low_base; 554 | highslot=0; 555 | } else { 556 | return; 557 | } 558 | 559 | 560 | itoa_base10(rom_number_on_sdcard, &root_directory[root_directory_base_length]); 561 | 562 | res = f_opendir(&dir, root_directory); 563 | 564 | if (res == FR_OK) { 565 | for (;;) { 566 | res = f_readdir(&dir, &fno); /* Read a directory item */ 567 | if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */ 568 | strcpy(full_filename,root_directory); 569 | strcat(full_filename,"/"); 570 | strcat(full_filename,fno.fname); 571 | res = f_open(&fil, full_filename, FA_READ); 572 | if (res == FR_OK) { 573 | //printf(">>>opened %s 0x%08x\n",full_filename, swram); 574 | if (highslot) { 575 | swram += ((slot-12)<<14); 576 | res = f_read(&fil, swram, 16384, &BytesRead); 577 | } else { 578 | swram += ((slot-4)<<14); 579 | res = f_read(&fil, temp_rom, 16384, &BytesRead); 580 | memcpy(swram,temp_rom,16384); 581 | } 582 | 583 | if (res == FR_OK) { 584 | f_close(&fil); 585 | } 586 | } 587 | break; // only interested in the first file in the dir 588 | } 589 | f_closedir(&dir); 590 | } 591 | } 592 | 593 | void clear_rom_area(uint32_t *p) { 594 | for (int i = 0 ; i < 0x4000 ; i+= 0x1000) { 595 | p[i]=0; p[i+1]=0; // clear 8 bytes at start of each rom 596 | } 597 | 598 | } 599 | // probably dont need to turn the optimiser off, but it kept on annoying me at the time 600 | int __attribute__((optimize("O0"))) main(void) { 601 | FRESULT res; 602 | 603 | // FPU related 604 | enable_fpu_and_disable_lazy_stacking(); 605 | 606 | clear_rom_area((uint32_t *) &swram_high_base); 607 | clear_rom_area((uint32_t *) &swram_low_base); 608 | 609 | // Assign some of the FPU registers to be actually used as integer 'fast access' during the ISR 610 | // register types dont really matter, so long as we get the assignment to work. 611 | register uint32_t zero_register asm("s0") __attribute__((unused)) = 0; 612 | register uint32_t one_register asm("s1") __attribute__((unused)) = 1; 613 | 614 | register volatile unsigned char* copy_gpioc_base asm("s2") __attribute__((unused)) = (unsigned char*) GPIOC; 615 | register volatile unsigned char* copy_exti_base asm("s3") __attribute__((unused)) = (unsigned char*) EXTI; 616 | // combo register: 617 | // b31-b16 - Effectively a copy of the lower 16 bits of the MODER register (for controlling whether PD2 is a GPIO or Alt function (for SDIO) 618 | // b15-b8 - Current state of PD2. Either 04 for PD2=1, or 00 for PD2=0 619 | // b7-b0 - Current ROM slot register (updated when a 6502 write to FE05 occurs) 620 | register uint32_t copy_combo_register asm("s4") __attribute__((unused)) = 0x00100000; 621 | register volatile unsigned char* copy_gpioa_base asm("s5") __attribute__((unused)) = (unsigned char*) GPIOA; 622 | register volatile uint8_t* copy_swram_high_base asm("s6") __attribute__((unused)) = (volatile uint8_t*) &swram_high_base; 623 | register volatile uint8_t* copy_swram_low_base asm("s7") __attribute__((unused)) = (volatile uint8_t*) &swram_low_base; 624 | // 5555 = d15-d8 outputs and 0010 is d2 out 625 | register uint32_t copy_dataout_moder asm("s8") __attribute__((unused)) = 0x55550010; 626 | register uint32_t copy_adc_data asm("s9") __attribute__((unused)) = 0x00000000; 627 | // Use some of the high fpu registers as a sort of stack. eg. save r11 to s30 on ISR entry, then put it back on ISR exit 628 | register volatile uint8_t* fake_stack_r11 asm("s30") __attribute__((unused)); 629 | 630 | //__disable_irq(); 631 | // 632 | // If you define roms to load in roms-preloaded-from-flash.S, they will get loaded in here. 633 | copy_rom_to_ram(); 634 | 635 | #ifdef ENABLE_SEMIHOSTING 636 | initialise_monitor_handles(); /*rtt*/ 637 | printf("Semi hosting on\n"); 638 | #endif 639 | 640 | rcc_set_frequency(SYSCLK_240_MHZ); 641 | // switch on compensation cell 642 | RCC->APB2ENR |= 0 | RCC_APB2ENR_SYSCFGEN ; 643 | SYSCFG->CMPCR |= SYSCFG_CMPCR_CMP_PD; // enable compensation cell 644 | while ((SYSCFG->CMPCR & SYSCFG_CMPCR_READY) == 0); // wait until ready 645 | 646 | //__disable_irq(); 647 | 648 | // Enable CCMRAM clock 649 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CCMDATARAMEN, ENABLE); 650 | 651 | config_backup_sram(); 652 | 653 | config_gpio_data(); 654 | 655 | config_gpio_addr(); 656 | 657 | config_gpio_portc(); 658 | 659 | config_gpio_dbg(); 660 | 661 | //NVIC_SystemLPConfig(NVIC_LP_SEVONPEND, ENABLE); 662 | NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); 663 | 664 | SysTick->CTRL = 0; 665 | 666 | ADC_Config(); 667 | 668 | memset(&fs32, 0, sizeof(FATFS)); 669 | 670 | // Change to lazy mounting the SD card 671 | res = f_mount(&fs32, "",0); 672 | 673 | 674 | if (res != FR_OK) { 675 | #ifdef SEMIHOSTING_SDCARD 676 | printf("Failed to mount. Error = %d\n",res); 677 | #endif 678 | // TODO. Flash some LED or something if the SD card does not mount 679 | while (1); 680 | } else { 681 | #ifdef SEMIHOSTING_SDCARD 682 | printf("mounted ok\n"); 683 | #endif 684 | } 685 | 686 | // Look for ROM images on the SD card and load them 687 | scan_and_load_roms(); 688 | //f_mount(0, "1:", 1); // unmount 689 | 690 | config_PC0_int(); 691 | 692 | int check_adc_conversion_finished = 0; 693 | uint16_t adc_value; 694 | while(1) { 695 | if (check_adc_conversion_finished) { 696 | // check if conversion complete 697 | if (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)) { 698 | adc_value = ADC_GetConversionValue(ADC1); 699 | // try to adjust the analog value at the extremes (in case the potentiometers in the joystick dont go all the way to 0 or 255) 700 | if (adc_value < ADC_LOW_THRESHOLD) { 701 | adc_value=0; 702 | } else if (adc_value > ADC_HIGH_THRESHOLD) { 703 | adc_value = 255; 704 | } 705 | 706 | // put adc value in lowest byte of s9. Clear b31 of s9 to say value available 707 | // NB: We lose the channel id out of s9 at this point. Not the end of the world. 708 | __asm volatile ("mov r3,%[adc_value] \n bfc r3,#31,#1 \n vmov s9,r3 "::[adc_value] "r" (adc_value) : "r3"); 709 | check_adc_conversion_finished=0; 710 | } 711 | } 712 | 713 | if (!(main_thread_command & 0xc0000000) && (main_thread_command & MAIN_THREAD_COMMANDS_MASK)) { 714 | switch (main_thread_command & MAIN_THREAD_COMMANDS_MASK) { 715 | case (MAIN_THREAD_ROM_SWAP_COMMAND): 716 | // LOAD A NEW ROM INTO A SLOT 717 | main_thread_command |= 0x40000000; 718 | 719 | load_rom( ((main_thread_command & 0x00000f00)>>8), (main_thread_command & 0x000000ff) ); 720 | 721 | main_thread_command = 0x00000000; 722 | 723 | break; 724 | case (MAIN_THREAD_REQUEST_ADC_CONVERSION_COMMAND): 725 | main_thread_command |= 0x40000000; 726 | // Start conversion of channel 2, or channel 3, or channel 4 etc. 727 | ADC_RegularChannelConfig(ADC1, (uint8_t) ((main_thread_command & 0x00000003)+2), 1, ADC_SampleTime_480Cycles); 728 | //ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_84Cycles); 729 | ADC_SoftwareStartConv(ADC1); 730 | 731 | check_adc_conversion_finished=1; 732 | main_thread_command = 0x00000000; 733 | break; 734 | default: 735 | main_thread_command = 0x00000000; 736 | break; 737 | 738 | } 739 | } 740 | } 741 | } 742 | 743 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | #ifndef __MAIN_H 2 | #define __MAIN_H 3 | 4 | #define MAIN_THREAD_ROM_SWAP_COMMAND 0x20000000 //b29 5 | #define MAIN_THREAD_REQUEST_ADC_CONVERSION_COMMAND 0x10000000 //b28 6 | #define MAIN_THREAD_COMMANDS_MASK (MAIN_THREAD_ROM_SWAP_COMMAND | MAIN_THREAD_REQUEST_ADC_CONVERSION_COMMAND) 7 | //#define MAIN_THREAD_COMMANDS_MASK (MAIN_THREAD_ROM_SWAP_COMMAND) 8 | 9 | // If your joystick can go from one extreme to the other then maybe use 0 to 255 10 | #define ADC_LOW_THRESHOLD 0 11 | #define ADC_HIGH_THRESHOLD 255 12 | 13 | // If your joystick does not go full swing from 0 to 255, you might need these 'jump thresholds' to help 14 | //#define ADC_LOW_THRESHOLD 64 15 | //#define ADC_HIGH_THRESHOLD 192 16 | 17 | #endif 18 | 19 | -------------------------------------------------------------------------------- /roms-preloaded-from-flash.S: -------------------------------------------------------------------------------- 1 | /* 2 | List rom files in here that you would like to compile in to 3 | the flash (firmware image) at build time. Just have one .incbin 4 | line after the label for the rom slot number. 5 | */ 6 | 7 | slot_4_base: 8 | //.incbin "roms/ESWMMFS.rom" 9 | slot_5_base: 10 | //.incbin "roms/AP6v130ta.rom" 11 | slot_6_base: 12 | //.incbin "roms/blank.rom" 13 | slot_7_base: 14 | //.incbin "roms/blank.rom" 15 | slot_12_base: 16 | //.incbin "roms/blank.rom" 17 | slot_13_base: 18 | //.incbin "roms/blank.rom" 19 | slot_14_base: 20 | //.incbin "roms/blank.rom" 21 | slot_15_base: 22 | //.incbin "roms/blank.rom" 23 | slots_end: 24 | -------------------------------------------------------------------------------- /roms/README.md: -------------------------------------------------------------------------------- 1 | Copy Electron 16KB ROMs in here and reference them from poller.S 2 | -------------------------------------------------------------------------------- /roms/blank.rom: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sdmm.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------/ 2 | / Foolproof MMCv3/SDv1/SDv2 (in SPI mode) control module 3 | /-------------------------------------------------------------------------/ 4 | / 5 | / Copyright (C) 2013, 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 | Features and Limitations: 14 | 15 | * Easy to Port Bit-banging SPI 16 | It uses only four GPIO pins. No complex peripheral needs to be used. 17 | 18 | * Platform Independent 19 | You need to modify only a few macros to control the GPIO port. 20 | 21 | * Low Speed 22 | The data transfer rate will be several times slower than hardware SPI. 23 | 24 | * No Media Change Detection 25 | Application program needs to perform a f_mount() after media change. 26 | 27 | /-------------------------------------------------------------------------*/ 28 | 29 | #ifdef SEMIHOSTING_SDCARD 30 | #include 31 | #endif 32 | #include "diskio.h" /* Common include file for FatFs and disk I/O layer */ 33 | #include "stm32f4xx.h" 34 | 35 | // Need to still induce a delay for bitbanging in fast mode 36 | #define NOPS __asm volatile ( "nop \n nop\n nop \n nop") 37 | 38 | uint32_t portc_state; 39 | 40 | 41 | /*-------------------------------------------------------------------------*/ 42 | /* Platform dependent macros and functions needed to be modified */ 43 | /*-------------------------------------------------------------------------*/ 44 | 45 | //#include /* Include device specific declareation file here */ 46 | 47 | 48 | // MOSI is DI 49 | // MISO is DO 50 | // 51 | // /CS - PC11 52 | // MOSI/DI - PD2 53 | // SCK - PC12 54 | // MISO/DO - PC8 55 | 56 | // I do all the init in main.c 57 | // 58 | //#define DO_INIT() /* Initialize port for MMC DO as input */ 59 | #define DO (GPIOC->IDR & 0x0100) /* Test for MMC DO ('H':true, 'L':false) */ 60 | 61 | //#define DI_INIT() DDRB |= 0x02 /* Initialize port for MMC DI as output */ 62 | // This weirdness with s4 is because the ISR uses s4 to hold a few things including the state of PD2(DI) . When we send PD2 high, we also need to set the bit 63 | // in s4 so that the ISR will also set PD2 if it happens to do a 6502 read (ie. a write from the ISR's perspective). 64 | //#define DI_H() __asm volatile ( "vmov r3,s4 \n orr r3,#0x0400 \n vmov s4,r3 ":::"r3"); GPIOD->BSRRL = 1<<2 /* Set MMC DI "high" */ 65 | //#define DI_L() __asm volatile ( "vmov r3,s4 \n bfc r3,#10,#1 \n vmov s4,r3 ":::"r3"); GPIOD->BSRRH = 1<<2 /* Set MMC DI "low" */ 66 | #define DI_H() __asm volatile ( "vmov r3,s4 \n orr r3,#0x0400 \n vmov s4,r3 \n movs r3,#4 \n movw r4,#0x0c00 \n movt r4,#0x4002 \n str r3,[r4,#0x14] ":::"r3","r4"); /* Set MMC DI "high" */ 67 | #define DI_L() __asm volatile ( "vmov r3,s4 \n bfc r3,#10,#1 \n vmov s4,r3 \n movs r3,#0 \n movw r4, #0x0c00 \n movt r4,#0x4002 \n str r3,[r4,#0x14]":::"r3", "r4"); /* Set MMC DI "low" */ 68 | 69 | //#define CK_INIT() DDRB |= 0x04 /* Initialize port for MMC SCLK as output */ 70 | //#define CK_H() GPIOC->BSRRL = 1<<12 /* Set MMC SCLK "high" */ 71 | //#define CK_L() GPIOC->BSRRH = 1<<12 /* Set MMC SCLK "low" */ 72 | #define CK_H() portc_state |= 1<<12 ; GPIOC->ODR = portc_state; 73 | #define CK_L() portc_state &= ~(1 << 12); GPIOC->ODR = portc_state; 74 | 75 | //#define CS_INIT() DDRB |= 0x08 /* Initialize port for MMC CS as output */ 76 | //#define CS_H() GPIOC->BSRRL = 1<<11 /* Set MMC CS "high" */ 77 | //#define CS_L() GPIOC->BSRRH = 1<<11 /* Set MMC CS "low" */ 78 | #define CS_H() portc_state |= 1<<11 ; GPIOC->ODR = portc_state; 79 | #define CS_L() portc_state &= ~(1<<11) ; GPIOC->ODR = portc_state; 80 | 81 | 82 | static void dly_us(UINT n) 83 | { 84 | uint32_t i = n * 60; 85 | while (i-- > 0) { 86 | __asm volatile ("nop"); 87 | } 88 | } 89 | 90 | 91 | 92 | 93 | /*-------------------------------------------------------------------------- 94 | 95 | Module Private Functions 96 | 97 | ---------------------------------------------------------------------------*/ 98 | 99 | /* MMC/SD command (SPI mode) */ 100 | #define CMD0 (0) /* GO_IDLE_STATE */ 101 | #define CMD1 (1) /* SEND_OP_COND */ 102 | #define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */ 103 | #define CMD8 (8) /* SEND_IF_COND */ 104 | #define CMD9 (9) /* SEND_CSD */ 105 | #define CMD10 (10) /* SEND_CID */ 106 | #define CMD12 (12) /* STOP_TRANSMISSION */ 107 | #define CMD13 (13) /* SEND_STATUS */ 108 | #define ACMD13 (0x80+13) /* SD_STATUS (SDC) */ 109 | #define CMD16 (16) /* SET_BLOCKLEN */ 110 | #define CMD17 (17) /* READ_SINGLE_BLOCK */ 111 | #define CMD18 (18) /* READ_MULTIPLE_BLOCK */ 112 | #define CMD23 (23) /* SET_BLOCK_COUNT */ 113 | #define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ 114 | #define CMD24 (24) /* WRITE_BLOCK */ 115 | #define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ 116 | #define CMD32 (32) /* ERASE_ER_BLK_START */ 117 | #define CMD33 (33) /* ERASE_ER_BLK_END */ 118 | #define CMD38 (38) /* ERASE */ 119 | #define CMD55 (55) /* APP_CMD */ 120 | #define CMD58 (58) /* READ_OCR */ 121 | 122 | 123 | static 124 | DSTATUS Stat = STA_NOINIT; /* Disk status */ 125 | 126 | static 127 | BYTE CardType; /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */ 128 | 129 | // Start off with a slow clock rate. Set to 0 later to switch to faster SPI 130 | static 131 | BYTE BitDelay = 3; 132 | 133 | 134 | /*-----------------------------------------------------------------------*/ 135 | /* Transmit bytes to the card (bitbanging) */ 136 | /*-----------------------------------------------------------------------*/ 137 | 138 | static 139 | void xmit_mmc ( 140 | const BYTE* buff, /* Data to be sent */ 141 | UINT bc /* Number of bytes to send */ 142 | ) 143 | { 144 | BYTE d; 145 | if (!BitDelay) { 146 | do { 147 | d = *buff++; /* Get a byte to be sent */ 148 | if (d & 0x80) { DI_H(); } else { DI_L(); } /* bit7 */ 149 | NOPS; CK_H(); NOPS ; CK_L(); 150 | if (d & 0x40) { DI_H(); } else { DI_L(); } /* bit6 */ 151 | NOPS; CK_H(); NOPS ; CK_L(); 152 | if (d & 0x20) { DI_H(); } else { DI_L(); } /* bit5 */ 153 | NOPS; CK_H(); NOPS ; CK_L(); 154 | if (d & 0x10) { DI_H(); } else { DI_L(); } /* bit4 */ 155 | NOPS; CK_H(); NOPS ; CK_L(); 156 | if (d & 0x08) { DI_H(); } else { DI_L(); } /* bit3 */ 157 | NOPS; CK_H(); NOPS ; CK_L(); 158 | if (d & 0x04) { DI_H(); } else { DI_L(); } /* bit2 */ 159 | NOPS; CK_H(); NOPS ; CK_L(); 160 | if (d & 0x02) { DI_H(); } else { DI_L(); } /* bit1 */ 161 | NOPS; CK_H(); NOPS ; CK_L(); 162 | if (d & 0x01) { DI_H(); } else { DI_L(); } /* bit0 */ 163 | NOPS; CK_H(); NOPS ; CK_L(); 164 | } while (--bc); 165 | } else { 166 | 167 | do { 168 | d = *buff++; /* Get a byte to be sent */ 169 | if (d & 0x80) { DI_H(); } else { DI_L(); } /* bit7 */ 170 | dly_us(BitDelay); CK_H(); dly_us(BitDelay); CK_L(); 171 | if (d & 0x40) { DI_H(); } else { DI_L(); } /* bit6 */ 172 | dly_us(BitDelay); CK_H(); dly_us(BitDelay); CK_L(); 173 | if (d & 0x20) { DI_H(); } else { DI_L(); } /* bit5 */ 174 | dly_us(BitDelay); CK_H(); dly_us(BitDelay); CK_L(); 175 | if (d & 0x10) { DI_H(); } else { DI_L(); } /* bit4 */ 176 | dly_us(BitDelay); CK_H(); dly_us(BitDelay); CK_L(); 177 | if (d & 0x08) { DI_H(); } else { DI_L(); } /* bit3 */ 178 | dly_us(BitDelay); CK_H(); dly_us(BitDelay); CK_L(); 179 | if (d & 0x04) { DI_H(); } else { DI_L(); } /* bit2 */ 180 | dly_us(BitDelay); CK_H(); dly_us(BitDelay); CK_L(); 181 | if (d & 0x02) { DI_H(); } else { DI_L(); } /* bit1 */ 182 | dly_us(BitDelay); CK_H(); dly_us(BitDelay); CK_L(); 183 | if (d & 0x01) { DI_H(); } else { DI_L(); } /* bit0 */ 184 | dly_us(BitDelay); CK_H(); dly_us(BitDelay); CK_L(); 185 | } while (--bc); 186 | } 187 | 188 | } 189 | 190 | 191 | 192 | /*-----------------------------------------------------------------------*/ 193 | /* Receive bytes from the card (bitbanging) */ 194 | /*-----------------------------------------------------------------------*/ 195 | 196 | static 197 | void rcvr_mmc ( 198 | BYTE *buff, /* Pointer to read buffer */ 199 | UINT bc /* Number of bytes to receive */ 200 | ) 201 | { 202 | BYTE r; 203 | DI_H(); /* Send 0xFF */ 204 | 205 | if (!BitDelay) { 206 | NOPS; 207 | do { 208 | r = 0; if (DO) r++; /* bit7 */ 209 | CK_H(); NOPS; CK_L(); 210 | NOPS; 211 | r <<= 1; if (DO) r++; /* bit6 */ 212 | CK_H(); NOPS; CK_L(); 213 | NOPS; 214 | r <<= 1; if (DO) r++; /* bit5 */ 215 | CK_H(); NOPS; CK_L(); 216 | NOPS; 217 | r <<= 1; if (DO) r++; /* bit4 */ 218 | CK_H(); NOPS; CK_L(); 219 | NOPS; 220 | r <<= 1; if (DO) r++; /* bit3 */ 221 | CK_H(); NOPS; CK_L(); 222 | NOPS; 223 | r <<= 1; if (DO) r++; /* bit2 */ 224 | CK_H(); NOPS; CK_L(); 225 | NOPS; 226 | r <<= 1; if (DO) r++; /* bit1 */ 227 | CK_H(); NOPS; CK_L(); 228 | NOPS; 229 | r <<= 1; if (DO) r++; /* bit0 */ 230 | CK_H(); NOPS; CK_L(); 231 | NOPS; 232 | *buff++ = r; /* Store a received byte */ 233 | } while (--bc); 234 | } else { 235 | dly_us(BitDelay); 236 | do { 237 | r = 0; if (DO) r++; /* bit7 */ 238 | CK_H(); dly_us(BitDelay); CK_L(); dly_us(BitDelay); 239 | r <<= 1; if (DO) r++; /* bit6 */ 240 | CK_H(); dly_us(BitDelay); CK_L(); dly_us(BitDelay); 241 | r <<= 1; if (DO) r++; /* bit5 */ 242 | CK_H(); dly_us(BitDelay); CK_L(); dly_us(BitDelay); 243 | r <<= 1; if (DO) r++; /* bit4 */ 244 | CK_H(); dly_us(BitDelay); CK_L(); dly_us(BitDelay); 245 | r <<= 1; if (DO) r++; /* bit3 */ 246 | CK_H(); dly_us(BitDelay); CK_L(); dly_us(BitDelay); 247 | r <<= 1; if (DO) r++; /* bit2 */ 248 | CK_H(); dly_us(BitDelay); CK_L(); dly_us(BitDelay); 249 | r <<= 1; if (DO) r++; /* bit1 */ 250 | CK_H(); dly_us(BitDelay); CK_L(); dly_us(BitDelay); 251 | r <<= 1; if (DO) r++; /* bit0 */ 252 | CK_H(); dly_us(BitDelay); CK_L(); dly_us(BitDelay); 253 | *buff++ = r; /* Store a received byte */ 254 | } while (--bc); 255 | } 256 | 257 | } 258 | 259 | 260 | /*-----------------------------------------------------------------------*/ 261 | /* Wait for card ready */ 262 | /*-----------------------------------------------------------------------*/ 263 | 264 | static 265 | int wait_ready (void) /* 1:OK, 0:Timeout */ 266 | { 267 | BYTE d; 268 | UINT tmr; 269 | 270 | 271 | for (tmr = 5000; tmr; tmr--) { /* Wait for ready in timeout of 500ms */ 272 | rcvr_mmc(&d, 1); 273 | if (d == 0xFF) break; 274 | dly_us(100); 275 | } 276 | 277 | return tmr ? 1 : 0; 278 | } 279 | 280 | 281 | 282 | /*-----------------------------------------------------------------------*/ 283 | /* Deselect the card and release SPI bus */ 284 | /*-----------------------------------------------------------------------*/ 285 | 286 | static 287 | void deselect (void) 288 | { 289 | BYTE d; 290 | 291 | CS_H(); /* Set CS# high */ 292 | rcvr_mmc(&d, 1); /* Dummy clock (force DO hi-z for multiple slave SPI) */ 293 | } 294 | 295 | 296 | 297 | /*-----------------------------------------------------------------------*/ 298 | /* Select the card and wait for ready */ 299 | /*-----------------------------------------------------------------------*/ 300 | 301 | static 302 | int sdmm_select (void) /* 1:OK, 0:Timeout */ 303 | { 304 | BYTE d; 305 | 306 | CS_L(); /* Set CS# low */ 307 | rcvr_mmc(&d, 1); /* Dummy clock (force DO enabled) */ 308 | if (wait_ready()) return 1; /* Wait for card ready */ 309 | 310 | deselect(); 311 | return 0; /* Failed */ 312 | } 313 | 314 | 315 | 316 | /*-----------------------------------------------------------------------*/ 317 | /* Receive a data packet from the card */ 318 | /*-----------------------------------------------------------------------*/ 319 | 320 | static 321 | int rcvr_datablock ( /* 1:OK, 0:Failed */ 322 | BYTE *buff, /* Data buffer to store received data */ 323 | UINT btr /* Byte count */ 324 | ) 325 | { 326 | BYTE d[2]; 327 | UINT tmr; 328 | 329 | 330 | for (tmr = 1000; tmr; tmr--) { /* Wait for data packet in timeout of 100ms */ 331 | rcvr_mmc(d, 1); 332 | if (d[0] != 0xFF) break; 333 | dly_us(100); 334 | } 335 | if (d[0] != 0xFE) return 0; /* If not valid data token, return with error */ 336 | 337 | rcvr_mmc(buff, btr); /* Receive the data block into buffer */ 338 | rcvr_mmc(d, 2); /* Discard CRC */ 339 | 340 | return 1; /* Return with success */ 341 | } 342 | 343 | 344 | 345 | /*-----------------------------------------------------------------------*/ 346 | /* Send a data packet to the card */ 347 | /*-----------------------------------------------------------------------*/ 348 | 349 | static 350 | int xmit_datablock ( /* 1:OK, 0:Failed */ 351 | const BYTE *buff, /* 512 byte data block to be transmitted */ 352 | BYTE token /* Data/Stop token */ 353 | ) 354 | { 355 | BYTE d[2]; 356 | 357 | 358 | if (!wait_ready()) return 0; 359 | 360 | d[0] = token; 361 | xmit_mmc(d, 1); /* Xmit a token */ 362 | if (token != 0xFD) { /* Is it data token? */ 363 | xmit_mmc(buff, 512); /* Xmit the 512 byte data block to MMC */ 364 | rcvr_mmc(d, 2); /* Xmit dummy CRC (0xFF,0xFF) */ 365 | rcvr_mmc(d, 1); /* Receive data response */ 366 | if ((d[0] & 0x1F) != 0x05) /* If not accepted, return with error */ 367 | return 0; 368 | } 369 | 370 | return 1; 371 | } 372 | 373 | 374 | 375 | /*-----------------------------------------------------------------------*/ 376 | /* Send a command packet to the card */ 377 | /*-----------------------------------------------------------------------*/ 378 | 379 | static 380 | BYTE send_cmd ( /* Returns command response (bit7==1:Send failed)*/ 381 | BYTE cmd, /* Command byte */ 382 | DWORD arg /* Argument */ 383 | ) 384 | { 385 | BYTE n, d, buf[6]; 386 | 387 | 388 | 389 | if (cmd & 0x80) { /* ACMD is the command sequense of CMD55-CMD */ 390 | cmd &= 0x7F; 391 | n = send_cmd(CMD55, 0); 392 | if (n > 1) return n; 393 | } 394 | 395 | /* Select the card and wait for ready except to stop multiple block read */ 396 | if (cmd != CMD12) { 397 | deselect(); 398 | if (!sdmm_select()) return 0xFF; 399 | } 400 | 401 | /* Send a command packet */ 402 | buf[0] = 0x40 | cmd; /* Start + Command index */ 403 | buf[1] = (BYTE)(arg >> 24); /* Argument[31..24] */ 404 | buf[2] = (BYTE)(arg >> 16); /* Argument[23..16] */ 405 | buf[3] = (BYTE)(arg >> 8); /* Argument[15..8] */ 406 | buf[4] = (BYTE)arg; /* Argument[7..0] */ 407 | n = 0x01; /* Dummy CRC + Stop */ 408 | if (cmd == CMD0) n = 0x95; /* (valid CRC for CMD0(0)) */ 409 | if (cmd == CMD8) n = 0x87; /* (valid CRC for CMD8(0x1AA)) */ 410 | buf[5] = n; 411 | xmit_mmc(buf, 6); 412 | 413 | /* Receive command response */ 414 | if (cmd == CMD12) rcvr_mmc(&d, 1); /* Skip a stuff byte when stop reading */ 415 | n = 10; /* Wait for a valid response in timeout of 10 attempts */ 416 | do 417 | rcvr_mmc(&d, 1); 418 | while ((d & 0x80) && --n); 419 | 420 | return d; /* Return with the response value */ 421 | } 422 | 423 | 424 | 425 | /*-------------------------------------------------------------------------- 426 | 427 | Public Functions 428 | 429 | ---------------------------------------------------------------------------*/ 430 | 431 | 432 | /*-----------------------------------------------------------------------*/ 433 | /* Get Disk Status */ 434 | /*-----------------------------------------------------------------------*/ 435 | 436 | DSTATUS disk_status ( 437 | BYTE drv /* Drive number (always 0) */ 438 | ) 439 | { 440 | if (drv) return STA_NOINIT; 441 | 442 | return Stat; 443 | } 444 | 445 | 446 | 447 | /*-----------------------------------------------------------------------*/ 448 | /* Initialize Disk Drive */ 449 | /*-----------------------------------------------------------------------*/ 450 | 451 | DSTATUS disk_initialize ( 452 | BYTE drv /* Physical drive nmuber (0) */ 453 | ) 454 | { 455 | BYTE n, ty, cmd, buf[4]; 456 | UINT tmr; 457 | DSTATUS s; 458 | 459 | #ifdef SEMIHOSTING_SDCARD 460 | printf("disk_initialize\n"); 461 | #endif 462 | if (drv) return RES_NOTRDY; 463 | 464 | dly_us(10000); /* 10ms */ 465 | // assume GPIO is already initialised 466 | //CS_INIT(); CS_H(); /* Initialize port pin tied to CS */ 467 | //CK_INIT(); CK_L(); /* Initialize port pin tied to SCLK */ 468 | //DI_INIT(); /* Initialize port pin tied to DI */ 469 | //DO_INIT(); /* Initialize port pin tied to DO */ 470 | CS_H(); /* Initialize port pin tied to CS */ 471 | CK_L(); /* Initialize port pin tied to SCLK */ 472 | 473 | for (n = 10; n; n--) rcvr_mmc(buf, 1); /* Apply 80 dummy clocks and the card gets ready to receive command */ 474 | 475 | ty = 0; 476 | if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ 477 | #ifdef SEMIHOSTING_SDCARD 478 | printf("CMD0 OK\n"); 479 | #endif 480 | if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */ 481 | #ifdef SEMIHOSTING_SDCARD 482 | printf("CMD8 SDv2 OK\n"); 483 | #endif 484 | rcvr_mmc(buf, 4); /* Get trailing return value of R7 resp */ 485 | if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ 486 | for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */ 487 | if (send_cmd(ACMD41, 1UL << 30) == 0) break; 488 | dly_us(1000); 489 | } 490 | if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ 491 | rcvr_mmc(buf, 4); 492 | ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */ 493 | } 494 | } 495 | } else { /* SDv1 or MMCv3 */ 496 | #ifdef SEMIHOSTING_SDCARD 497 | printf("CMD8 SDv1 or MMCv3 OK\n"); 498 | #endif 499 | if (send_cmd(ACMD41, 0) <= 1) { 500 | ty = CT_SD1; cmd = ACMD41; /* SDv1 */ 501 | } else { 502 | ty = CT_MMC; cmd = CMD1; /* MMCv3 */ 503 | } 504 | for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */ 505 | if (send_cmd(cmd, 0) == 0) break; 506 | dly_us(1000); 507 | } 508 | if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ 509 | ty = 0; 510 | } 511 | } 512 | #ifdef SEMIHOSTING_SDCARD 513 | else { 514 | printf("CMD0 failed\n"); 515 | } 516 | #endif 517 | 518 | 519 | CardType = ty; 520 | s = ty ? 0 : STA_NOINIT; 521 | Stat = s; 522 | 523 | deselect(); 524 | 525 | // Switch to higher speed 526 | //BitDelay=2; 527 | BitDelay=0; 528 | 529 | return s; 530 | } 531 | 532 | 533 | 534 | /*-----------------------------------------------------------------------*/ 535 | /* Read Sector(s) */ 536 | /*-----------------------------------------------------------------------*/ 537 | 538 | DRESULT disk_read ( 539 | BYTE drv, /* Physical drive nmuber (0) */ 540 | BYTE *buff, /* Pointer to the data buffer to store read data */ 541 | DWORD sector, /* Start sector number (LBA) */ 542 | UINT count /* Sector count (1..128) */ 543 | ) 544 | { 545 | BYTE cmd; 546 | 547 | #ifdef SEMIHOSTING_SDCARD 548 | printf("disk_read %d %p %10d %d\n",drv,buff,sector,count); 549 | #endif 550 | 551 | if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY; 552 | if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert LBA to byte address if needed */ 553 | 554 | cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */ 555 | if (send_cmd(cmd, sector) == 0) { 556 | do { 557 | if (!rcvr_datablock(buff, 512)) break; 558 | buff += 512; 559 | } while (--count); 560 | if (cmd == CMD18) send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ 561 | } 562 | 563 | deselect(); 564 | #ifdef SEMIHOSTING_SDCARD 565 | printf("disk_read: count = %d\n",count); 566 | #endif 567 | return count ? RES_ERROR : RES_OK; 568 | } 569 | 570 | 571 | 572 | /*-----------------------------------------------------------------------*/ 573 | /* Write Sector(s) */ 574 | /*-----------------------------------------------------------------------*/ 575 | 576 | DRESULT disk_write ( 577 | BYTE drv, /* Physical drive nmuber (0) */ 578 | const BYTE *buff, /* Pointer to the data to be written */ 579 | DWORD sector, /* Start sector number (LBA) */ 580 | UINT count /* Sector count (1..128) */ 581 | ) 582 | { 583 | if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY; 584 | if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert LBA to byte address if needed */ 585 | 586 | if (count == 1) { /* Single block write */ 587 | if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */ 588 | && xmit_datablock(buff, 0xFE)) 589 | count = 0; 590 | } 591 | else { /* Multiple block write */ 592 | if (CardType & CT_SDC) send_cmd(ACMD23, count); 593 | if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */ 594 | do { 595 | if (!xmit_datablock(buff, 0xFC)) break; 596 | buff += 512; 597 | } while (--count); 598 | if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */ 599 | count = 1; 600 | } 601 | } 602 | deselect(); 603 | 604 | return count ? RES_ERROR : RES_OK; 605 | } 606 | 607 | 608 | /*-----------------------------------------------------------------------*/ 609 | /* Miscellaneous Functions */ 610 | /*-----------------------------------------------------------------------*/ 611 | 612 | DRESULT disk_ioctl ( 613 | BYTE drv, /* Physical drive nmuber (0) */ 614 | BYTE ctrl, /* Control code */ 615 | void *buff /* Buffer to send/receive control data */ 616 | ) 617 | { 618 | DRESULT res; 619 | BYTE n, csd[16]; 620 | DWORD cs; 621 | 622 | 623 | if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY; /* Check if card is in the socket */ 624 | 625 | res = RES_ERROR; 626 | switch (ctrl) { 627 | case CTRL_SYNC : /* Make sure that no pending write process */ 628 | if (sdmm_select()) res = RES_OK; 629 | break; 630 | 631 | case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */ 632 | if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { 633 | if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ 634 | cs = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1; 635 | *(DWORD*)buff = cs << 10; 636 | } else { /* SDC ver 1.XX or MMC */ 637 | n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; 638 | cs = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; 639 | *(DWORD*)buff = cs << (n - 9); 640 | } 641 | res = RES_OK; 642 | } 643 | break; 644 | 645 | case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ 646 | *(DWORD*)buff = 128; 647 | res = RES_OK; 648 | break; 649 | 650 | default: 651 | res = RES_PARERR; 652 | } 653 | 654 | deselect(); 655 | 656 | return res; 657 | } 658 | 659 | /*-----------------------------------------------------------------------*/ 660 | /* Get current time */ 661 | /*-----------------------------------------------------------------------*/ 662 | DWORD get_fattime(void){ 663 | return 0; 664 | } 665 | 666 | -------------------------------------------------------------------------------- /startup_stm32f4xx.s: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file startup_stm32f4xx.s 4 | * @author MCD Application Team 5 | * @version V1.0.0 6 | * @date 30-September-2011 7 | * @brief STM32F4xx Devices vector table for Atollic TrueSTUDIO toolchain. 8 | * This module performs: 9 | * - Set the initial SP 10 | * - Set the initial PC == Reset_Handler, 11 | * - Set the vector table entries with the exceptions ISR address 12 | * - Configure the clock system and the external SRAM mounted on 13 | * STM324xG-EVAL board to be used as data memory (optional, 14 | * to be enabled by user) 15 | * - Branches to main in the C library (which eventually 16 | * calls main()). 17 | * After Reset the Cortex-M4 processor is in Thread mode, 18 | * priority is Privileged, and the Stack is set to Main. 19 | ****************************************************************************** 20 | * @attention 21 | * 22 | * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 23 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 24 | * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY 25 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 26 | * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 27 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 28 | * 29 | *

© COPYRIGHT 2011 STMicroelectronics

30 | ****************************************************************************** 31 | */ 32 | 33 | .syntax unified 34 | .cpu cortex-m3 35 | .fpu softvfp 36 | .thumb 37 | 38 | .global g_pfnVectors 39 | .global Default_Handler 40 | 41 | /* start address for the initialization values of the .data section. 42 | defined in linker script */ 43 | .word _sidata 44 | /* start address for the .data section. defined in linker script */ 45 | .word _sdata 46 | /* end address for the .data section. defined in linker script */ 47 | .word _edata 48 | /* start address for the .bss section. defined in linker script */ 49 | .word _sbss 50 | /* end address for the .bss section. defined in linker script */ 51 | .word _ebss 52 | /* stack used for SystemInit_ExtMemCtl; always internal RAM used */ 53 | 54 | /** 55 | * @brief This is the code that gets called when the processor first 56 | * starts execution following a reset event. Only the absolutely 57 | * necessary set is performed, after which the application 58 | * supplied main() routine is called. 59 | * @param None 60 | * @retval : None 61 | */ 62 | 63 | .section .text.Reset_Handler 64 | .weak Reset_Handler 65 | .type Reset_Handler, %function 66 | Reset_Handler: 67 | 68 | /* Copy the data segment initializers from flash to SRAM and CCMRAM*/ 69 | movs r1, #0 70 | b LoopCopyDataInit 71 | 72 | CopyDataInit: 73 | ldr r3, =_sidata 74 | ldr r3, [r3, r1] 75 | str r3, [r0, r1] 76 | adds r1, r1, #4 77 | 78 | LoopCopyDataInit: 79 | ldr r0, =_sdata 80 | ldr r3, =_edata 81 | adds r2, r0, r1 82 | cmp r2, r3 83 | bcc CopyDataInit 84 | movs r1, #0 85 | b LoopCopyDataInit1 86 | CopyDataInit1: 87 | ldr r3, =_siccmram 88 | ldr r3, [r3, r1] 89 | str r3, [r0, r1] 90 | adds r1, r1, #4 91 | LoopCopyDataInit1: 92 | ldr r0, =_sccmram 93 | ldr r3, =_eccmram 94 | adds r2, r0, r1 95 | cmp r2, r3 96 | bcc CopyDataInit1 97 | 98 | ldr r2, =_sbss 99 | b LoopFillZerobss 100 | /* Zero fill the bss segment. */ 101 | FillZerobss: 102 | movs r3, #0 103 | str r3, [r2], #4 104 | 105 | LoopFillZerobss: 106 | ldr r3, = _ebss 107 | cmp r2, r3 108 | bcc FillZerobss 109 | 110 | /* Call the clock system intitialization function.*/ 111 | bl SystemInit 112 | /* Call static constructors */ 113 | bl __libc_init_array 114 | /* Call the application's entry point.*/ 115 | bl main 116 | bx lr 117 | .size Reset_Handler, .-Reset_Handler 118 | 119 | /** 120 | * @brief This is the code that gets called when the processor receives an 121 | * unexpected interrupt. This simply enters an infinite loop, preserving 122 | * the system state for examination by a debugger. 123 | * @param None 124 | * @retval None 125 | */ 126 | .section .text.Default_Handler,"ax",%progbits 127 | Default_Handler: 128 | Infinite_Loop: 129 | b Infinite_Loop 130 | .size Default_Handler, .-Default_Handler 131 | /****************************************************************************** 132 | * 133 | * The minimal vector table for a Cortex M3. Note that the proper constructs 134 | * must be placed on this to ensure that it ends up at physical address 135 | * 0x0000.0000. 136 | * 137 | *******************************************************************************/ 138 | .section .isr_vector,"a",%progbits 139 | .type g_pfnVectors, %object 140 | .size g_pfnVectors, .-g_pfnVectors 141 | 142 | 143 | g_pfnVectors: 144 | .word _estack 145 | .word Reset_Handler 146 | .word NMI_Handler 147 | .word HardFault_Handler 148 | .word MemManage_Handler 149 | .word BusFault_Handler 150 | .word UsageFault_Handler 151 | .word 0 152 | .word 0 153 | .word 0 154 | .word 0 155 | .word SVC_Handler 156 | .word DebugMon_Handler 157 | .word 0 158 | .word PendSV_Handler 159 | .word SysTick_Handler 160 | 161 | /* External Interrupts */ 162 | .word WWDG_IRQHandler /* Window WatchDog */ 163 | .word PVD_IRQHandler /* PVD through EXTI Line detection */ 164 | .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ 165 | .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ 166 | .word FLASH_IRQHandler /* FLASH */ 167 | .word RCC_IRQHandler /* RCC */ 168 | .word EXTI0_IRQHandler /* EXTI Line0 */ 169 | .word EXTI1_IRQHandler /* EXTI Line1 */ 170 | .word EXTI2_IRQHandler /* EXTI Line2 */ 171 | .word EXTI3_IRQHandler /* EXTI Line3 */ 172 | .word EXTI4_IRQHandler /* EXTI Line4 */ 173 | .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ 174 | .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ 175 | .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ 176 | .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ 177 | .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ 178 | .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ 179 | .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ 180 | .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ 181 | .word CAN1_TX_IRQHandler /* CAN1 TX */ 182 | .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ 183 | .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ 184 | .word CAN1_SCE_IRQHandler /* CAN1 SCE */ 185 | .word EXTI9_5_IRQHandler /* External Line[9:5]s */ 186 | .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ 187 | .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ 188 | .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ 189 | .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ 190 | .word TIM2_IRQHandler /* TIM2 */ 191 | .word TIM3_IRQHandler /* TIM3 */ 192 | .word TIM4_IRQHandler /* TIM4 */ 193 | .word I2C1_EV_IRQHandler /* I2C1 Event */ 194 | .word I2C1_ER_IRQHandler /* I2C1 Error */ 195 | .word I2C2_EV_IRQHandler /* I2C2 Event */ 196 | .word I2C2_ER_IRQHandler /* I2C2 Error */ 197 | .word SPI1_IRQHandler /* SPI1 */ 198 | .word SPI2_IRQHandler /* SPI2 */ 199 | .word USART1_IRQHandler /* USART1 */ 200 | .word USART2_IRQHandler /* USART2 */ 201 | .word USART3_IRQHandler /* USART3 */ 202 | .word EXTI15_10_IRQHandler /* External Line[15:10]s */ 203 | .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ 204 | .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ 205 | .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ 206 | .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ 207 | .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ 208 | .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ 209 | .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ 210 | .word FSMC_IRQHandler /* FSMC */ 211 | .word SDIO_IRQHandler /* SDIO */ 212 | .word TIM5_IRQHandler /* TIM5 */ 213 | .word SPI3_IRQHandler /* SPI3 */ 214 | .word UART4_IRQHandler /* UART4 */ 215 | .word UART5_IRQHandler /* UART5 */ 216 | .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ 217 | .word TIM7_IRQHandler /* TIM7 */ 218 | .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ 219 | .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ 220 | .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ 221 | .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ 222 | .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ 223 | .word ETH_IRQHandler /* Ethernet */ 224 | .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ 225 | .word CAN2_TX_IRQHandler /* CAN2 TX */ 226 | .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ 227 | .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ 228 | .word CAN2_SCE_IRQHandler /* CAN2 SCE */ 229 | .word OTG_FS_IRQHandler /* USB OTG FS */ 230 | .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ 231 | .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ 232 | .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ 233 | .word USART6_IRQHandler /* USART6 */ 234 | .word I2C3_EV_IRQHandler /* I2C3 event */ 235 | .word I2C3_ER_IRQHandler /* I2C3 error */ 236 | .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ 237 | .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ 238 | .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ 239 | .word OTG_HS_IRQHandler /* USB OTG HS */ 240 | .word DCMI_IRQHandler /* DCMI */ 241 | .word CRYP_IRQHandler /* CRYP crypto */ 242 | .word HASH_RNG_IRQHandler /* Hash and Rng */ 243 | .word FPU_IRQHandler /* FPU */ 244 | 245 | 246 | /******************************************************************************* 247 | * 248 | * Provide weak aliases for each Exception handler to the Default_Handler. 249 | * As they are weak aliases, any function with the same name will override 250 | * this definition. 251 | * 252 | *******************************************************************************/ 253 | .weak NMI_Handler 254 | .thumb_set NMI_Handler,Default_Handler 255 | 256 | .weak HardFault_Handler 257 | .thumb_set HardFault_Handler,Default_Handler 258 | 259 | .weak MemManage_Handler 260 | .thumb_set MemManage_Handler,Default_Handler 261 | 262 | .weak BusFault_Handler 263 | .thumb_set BusFault_Handler,Default_Handler 264 | 265 | .weak UsageFault_Handler 266 | .thumb_set UsageFault_Handler,Default_Handler 267 | 268 | .weak SVC_Handler 269 | .thumb_set SVC_Handler,Default_Handler 270 | 271 | .weak DebugMon_Handler 272 | .thumb_set DebugMon_Handler,Default_Handler 273 | 274 | .weak PendSV_Handler 275 | .thumb_set PendSV_Handler,Default_Handler 276 | 277 | .weak SysTick_Handler 278 | .thumb_set SysTick_Handler,Default_Handler 279 | 280 | .weak WWDG_IRQHandler 281 | .thumb_set WWDG_IRQHandler,Default_Handler 282 | 283 | .weak PVD_IRQHandler 284 | .thumb_set PVD_IRQHandler,Default_Handler 285 | 286 | .weak TAMP_STAMP_IRQHandler 287 | .thumb_set TAMP_STAMP_IRQHandler,Default_Handler 288 | 289 | .weak RTC_WKUP_IRQHandler 290 | .thumb_set RTC_WKUP_IRQHandler,Default_Handler 291 | 292 | .weak FLASH_IRQHandler 293 | .thumb_set FLASH_IRQHandler,Default_Handler 294 | 295 | .weak RCC_IRQHandler 296 | .thumb_set RCC_IRQHandler,Default_Handler 297 | 298 | .weak EXTI0_IRQHandler 299 | .thumb_set EXTI0_IRQHandler,Default_Handler 300 | 301 | .weak EXTI1_IRQHandler 302 | .thumb_set EXTI1_IRQHandler,Default_Handler 303 | 304 | .weak EXTI2_IRQHandler 305 | .thumb_set EXTI2_IRQHandler,Default_Handler 306 | 307 | .weak EXTI3_IRQHandler 308 | .thumb_set EXTI3_IRQHandler,Default_Handler 309 | 310 | .weak EXTI4_IRQHandler 311 | .thumb_set EXTI4_IRQHandler,Default_Handler 312 | 313 | .weak DMA1_Stream0_IRQHandler 314 | .thumb_set DMA1_Stream0_IRQHandler,Default_Handler 315 | 316 | .weak DMA1_Stream1_IRQHandler 317 | .thumb_set DMA1_Stream1_IRQHandler,Default_Handler 318 | 319 | .weak DMA1_Stream2_IRQHandler 320 | .thumb_set DMA1_Stream2_IRQHandler,Default_Handler 321 | 322 | .weak DMA1_Stream3_IRQHandler 323 | .thumb_set DMA1_Stream3_IRQHandler,Default_Handler 324 | 325 | .weak DMA1_Stream4_IRQHandler 326 | .thumb_set DMA1_Stream4_IRQHandler,Default_Handler 327 | 328 | .weak DMA1_Stream5_IRQHandler 329 | .thumb_set DMA1_Stream5_IRQHandler,Default_Handler 330 | 331 | .weak DMA1_Stream6_IRQHandler 332 | .thumb_set DMA1_Stream6_IRQHandler,Default_Handler 333 | 334 | .weak ADC_IRQHandler 335 | .thumb_set ADC_IRQHandler,Default_Handler 336 | 337 | .weak CAN1_TX_IRQHandler 338 | .thumb_set CAN1_TX_IRQHandler,Default_Handler 339 | 340 | .weak CAN1_RX0_IRQHandler 341 | .thumb_set CAN1_RX0_IRQHandler,Default_Handler 342 | 343 | .weak CAN1_RX1_IRQHandler 344 | .thumb_set CAN1_RX1_IRQHandler,Default_Handler 345 | 346 | .weak CAN1_SCE_IRQHandler 347 | .thumb_set CAN1_SCE_IRQHandler,Default_Handler 348 | 349 | .weak EXTI9_5_IRQHandler 350 | .thumb_set EXTI9_5_IRQHandler,Default_Handler 351 | 352 | .weak TIM1_BRK_TIM9_IRQHandler 353 | .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler 354 | 355 | .weak TIM1_UP_TIM10_IRQHandler 356 | .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler 357 | 358 | .weak TIM1_TRG_COM_TIM11_IRQHandler 359 | .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler 360 | 361 | .weak TIM1_CC_IRQHandler 362 | .thumb_set TIM1_CC_IRQHandler,Default_Handler 363 | 364 | .weak TIM2_IRQHandler 365 | .thumb_set TIM2_IRQHandler,Default_Handler 366 | 367 | .weak TIM3_IRQHandler 368 | .thumb_set TIM3_IRQHandler,Default_Handler 369 | 370 | .weak TIM4_IRQHandler 371 | .thumb_set TIM4_IRQHandler,Default_Handler 372 | 373 | .weak I2C1_EV_IRQHandler 374 | .thumb_set I2C1_EV_IRQHandler,Default_Handler 375 | 376 | .weak I2C1_ER_IRQHandler 377 | .thumb_set I2C1_ER_IRQHandler,Default_Handler 378 | 379 | .weak I2C2_EV_IRQHandler 380 | .thumb_set I2C2_EV_IRQHandler,Default_Handler 381 | 382 | .weak I2C2_ER_IRQHandler 383 | .thumb_set I2C2_ER_IRQHandler,Default_Handler 384 | 385 | .weak SPI1_IRQHandler 386 | .thumb_set SPI1_IRQHandler,Default_Handler 387 | 388 | .weak SPI2_IRQHandler 389 | .thumb_set SPI2_IRQHandler,Default_Handler 390 | 391 | .weak USART1_IRQHandler 392 | .thumb_set USART1_IRQHandler,Default_Handler 393 | 394 | .weak USART2_IRQHandler 395 | .thumb_set USART2_IRQHandler,Default_Handler 396 | 397 | .weak USART3_IRQHandler 398 | .thumb_set USART3_IRQHandler,Default_Handler 399 | 400 | .weak EXTI15_10_IRQHandler 401 | .thumb_set EXTI15_10_IRQHandler,Default_Handler 402 | 403 | .weak RTC_Alarm_IRQHandler 404 | .thumb_set RTC_Alarm_IRQHandler,Default_Handler 405 | 406 | .weak OTG_FS_WKUP_IRQHandler 407 | .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler 408 | 409 | .weak TIM8_BRK_TIM12_IRQHandler 410 | .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler 411 | 412 | .weak TIM8_UP_TIM13_IRQHandler 413 | .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler 414 | 415 | .weak TIM8_TRG_COM_TIM14_IRQHandler 416 | .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler 417 | 418 | .weak TIM8_CC_IRQHandler 419 | .thumb_set TIM8_CC_IRQHandler,Default_Handler 420 | 421 | .weak DMA1_Stream7_IRQHandler 422 | .thumb_set DMA1_Stream7_IRQHandler,Default_Handler 423 | 424 | .weak FSMC_IRQHandler 425 | .thumb_set FSMC_IRQHandler,Default_Handler 426 | 427 | .weak SDIO_IRQHandler 428 | .thumb_set SDIO_IRQHandler,Default_Handler 429 | 430 | .weak TIM5_IRQHandler 431 | .thumb_set TIM5_IRQHandler,Default_Handler 432 | 433 | .weak SPI3_IRQHandler 434 | .thumb_set SPI3_IRQHandler,Default_Handler 435 | 436 | .weak UART4_IRQHandler 437 | .thumb_set UART4_IRQHandler,Default_Handler 438 | 439 | .weak UART5_IRQHandler 440 | .thumb_set UART5_IRQHandler,Default_Handler 441 | 442 | .weak TIM6_DAC_IRQHandler 443 | .thumb_set TIM6_DAC_IRQHandler,Default_Handler 444 | 445 | .weak TIM7_IRQHandler 446 | .thumb_set TIM7_IRQHandler,Default_Handler 447 | 448 | .weak DMA2_Stream0_IRQHandler 449 | .thumb_set DMA2_Stream0_IRQHandler,Default_Handler 450 | 451 | .weak DMA2_Stream1_IRQHandler 452 | .thumb_set DMA2_Stream1_IRQHandler,Default_Handler 453 | 454 | .weak DMA2_Stream2_IRQHandler 455 | .thumb_set DMA2_Stream2_IRQHandler,Default_Handler 456 | 457 | .weak DMA2_Stream3_IRQHandler 458 | .thumb_set DMA2_Stream3_IRQHandler,Default_Handler 459 | 460 | .weak DMA2_Stream4_IRQHandler 461 | .thumb_set DMA2_Stream4_IRQHandler,Default_Handler 462 | 463 | .weak ETH_IRQHandler 464 | .thumb_set ETH_IRQHandler,Default_Handler 465 | 466 | .weak ETH_WKUP_IRQHandler 467 | .thumb_set ETH_WKUP_IRQHandler,Default_Handler 468 | 469 | .weak CAN2_TX_IRQHandler 470 | .thumb_set CAN2_TX_IRQHandler,Default_Handler 471 | 472 | .weak CAN2_RX0_IRQHandler 473 | .thumb_set CAN2_RX0_IRQHandler,Default_Handler 474 | 475 | .weak CAN2_RX1_IRQHandler 476 | .thumb_set CAN2_RX1_IRQHandler,Default_Handler 477 | 478 | .weak CAN2_SCE_IRQHandler 479 | .thumb_set CAN2_SCE_IRQHandler,Default_Handler 480 | 481 | .weak OTG_FS_IRQHandler 482 | .thumb_set OTG_FS_IRQHandler,Default_Handler 483 | 484 | .weak DMA2_Stream5_IRQHandler 485 | .thumb_set DMA2_Stream5_IRQHandler,Default_Handler 486 | 487 | .weak DMA2_Stream6_IRQHandler 488 | .thumb_set DMA2_Stream6_IRQHandler,Default_Handler 489 | 490 | .weak DMA2_Stream7_IRQHandler 491 | .thumb_set DMA2_Stream7_IRQHandler,Default_Handler 492 | 493 | .weak USART6_IRQHandler 494 | .thumb_set USART6_IRQHandler,Default_Handler 495 | 496 | .weak I2C3_EV_IRQHandler 497 | .thumb_set I2C3_EV_IRQHandler,Default_Handler 498 | 499 | .weak I2C3_ER_IRQHandler 500 | .thumb_set I2C3_ER_IRQHandler,Default_Handler 501 | 502 | .weak OTG_HS_EP1_OUT_IRQHandler 503 | .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler 504 | 505 | .weak OTG_HS_EP1_IN_IRQHandler 506 | .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler 507 | 508 | .weak OTG_HS_WKUP_IRQHandler 509 | .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler 510 | 511 | .weak OTG_HS_IRQHandler 512 | .thumb_set OTG_HS_IRQHandler,Default_Handler 513 | 514 | .weak DCMI_IRQHandler 515 | .thumb_set DCMI_IRQHandler,Default_Handler 516 | 517 | .weak CRYP_IRQHandler 518 | .thumb_set CRYP_IRQHandler,Default_Handler 519 | 520 | .weak HASH_RNG_IRQHandler 521 | .thumb_set HASH_RNG_IRQHandler,Default_Handler 522 | 523 | .weak FPU_IRQHandler 524 | .thumb_set FPU_IRQHandler,Default_Handler 525 | 526 | /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ 527 | -------------------------------------------------------------------------------- /stm32_flash.ld: -------------------------------------------------------------------------------- 1 | /* 2 | ***************************************************************************** 3 | ** 4 | 5 | ** File : LinkerScript.ld 6 | ** 7 | ** Abstract : Linker script for STM32F407VGTx Device with 8 | ** 1024KByte FLASH, 128KByte RAM 9 | ** 10 | ** Set heap size, stack size and stack location according 11 | ** to application requirements. 12 | ** 13 | ** Set memory bank area and size if external memory is used. 14 | ** 15 | ** Target : STMicroelectronics STM32 16 | ** 17 | ** 18 | ** Distribution: The file is distributed as is, without any warranty 19 | ** of any kind. 20 | ** 21 | ** (c)Copyright Ac6. 22 | ** You may use this file as-is or modify it according to the needs of your 23 | ** project. Distribution of this file (unmodified or modified) is not 24 | ** permitted. Ac6 permit registered System Workbench for MCU users the 25 | ** rights to distribute the assembled, compiled & linked contents of this 26 | ** file as part of an application binary file, provided that it is built 27 | ** using the System Workbench for MCU toolchain. 28 | ** 29 | ***************************************************************************** 30 | */ 31 | 32 | /* Entry Point */ 33 | ENTRY(Reset_Handler) 34 | 35 | /* Highest address of the user mode stack */ 36 | _estack = 0x20020000; /* end of RAM */ 37 | /* _estack = 0x10010000; */ /* end of CCM RAM */ 38 | /* Generate a link error if heap and stack don't fit into RAM */ 39 | _Min_Heap_Size = 0x0800;; /* required amount of heap */ 40 | _Min_Stack_Size = 0x0800;; /* required amount of stack */ 41 | 42 | /* Specify the memory areas */ 43 | MEMORY 44 | { 45 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K 46 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K 47 | CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K 48 | 49 | } 50 | 51 | /* Define output sections */ 52 | SECTIONS 53 | { 54 | /* The startup code goes first into FLASH */ 55 | .isr_vector : 56 | { 57 | . = ALIGN(4); 58 | KEEP(*(.isr_vector)) /* Startup code */ 59 | . = ALIGN(4); 60 | } >FLASH 61 | 62 | /* The program code and other data goes into FLASH */ 63 | .text : 64 | { 65 | . = ALIGN(4); 66 | *(.text) /* .text sections (code) */ 67 | *(.text*) /* .text* sections (code) */ 68 | *(.glue_7) /* glue arm to thumb code */ 69 | *(.glue_7t) /* glue thumb to arm code */ 70 | *(.eh_frame) 71 | 72 | KEEP (*(.init)) 73 | KEEP (*(.fini)) 74 | 75 | . = ALIGN(4); 76 | _etext = .; /* define a global symbols at end of code */ 77 | } >FLASH 78 | 79 | /* Constant data goes into FLASH */ 80 | .rodata : 81 | { 82 | . = ALIGN(4); 83 | *(.rodata) /* .rodata sections (constants, strings, etc.) */ 84 | *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ 85 | . = ALIGN(4); 86 | } >FLASH 87 | 88 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH 89 | .ARM : { 90 | __exidx_start = .; 91 | *(.ARM.exidx*) 92 | __exidx_end = .; 93 | } >FLASH 94 | 95 | .preinit_array : 96 | { 97 | PROVIDE_HIDDEN (__preinit_array_start = .); 98 | KEEP (*(.preinit_array*)) 99 | PROVIDE_HIDDEN (__preinit_array_end = .); 100 | } >FLASH 101 | .init_array : 102 | { 103 | PROVIDE_HIDDEN (__init_array_start = .); 104 | KEEP (*(SORT(.init_array.*))) 105 | KEEP (*(.init_array*)) 106 | PROVIDE_HIDDEN (__init_array_end = .); 107 | } >FLASH 108 | .fini_array : 109 | { 110 | PROVIDE_HIDDEN (__fini_array_start = .); 111 | KEEP (*(SORT(.fini_array.*))) 112 | KEEP (*(.fini_array*)) 113 | PROVIDE_HIDDEN (__fini_array_end = .); 114 | } >FLASH 115 | 116 | /* used by the startup to initialize data */ 117 | _sidata = LOADADDR(.data); 118 | 119 | /* Initialized data sections goes into RAM, load LMA copy after code */ 120 | .data : 121 | { 122 | . = ALIGN(4); 123 | _sdata = .; /* create a global symbol at data start */ 124 | *(.data) /* .data sections */ 125 | *(.data*) /* .data* sections */ 126 | 127 | . = ALIGN(4); 128 | _edata = .; /* define a global symbol at data end */ 129 | } >RAM AT> FLASH 130 | 131 | _siccmram = LOADADDR(.ccmram); 132 | 133 | /* CCM-RAM section 134 | * 135 | * IMPORTANT NOTE! 136 | * If initialized variables will be placed in this section, 137 | * the startup code needs to be modified to copy the init-values. 138 | */ 139 | .ccmram : 140 | { 141 | . = ALIGN(4); 142 | _sccmram = .; /* create a global symbol at ccmram start */ 143 | swram_low_base = .; 144 | *(.ccmram) 145 | *(.ccmram*) 146 | 147 | . = ALIGN(4); 148 | _eccmram = .; /* create a global symbol at ccmram end */ 149 | } >CCMRAM AT> FLASH 150 | 151 | 152 | /* Uninitialized data section */ 153 | . = ALIGN(4); 154 | .bss : 155 | { 156 | /* This is used by the startup in order to initialize the .bss secion */ 157 | _sbss = .; /* define a global symbol at bss start */ 158 | __bss_start__ = _sbss; 159 | *(.bss) 160 | *(.bss*) 161 | *(COMMON) 162 | 163 | . = ALIGN(4); 164 | _ebss = .; /* define a global symbol at bss end */ 165 | __bss_end__ = _ebss; 166 | } >RAM 167 | 168 | /* User_heap_stack section, used to check that there is enough RAM left */ 169 | ._user_heap_stack : 170 | { 171 | . = ALIGN(4); 172 | PROVIDE ( end = . ); 173 | PROVIDE ( _end = . ); 174 | PROVIDE ( __end__ = . ); 175 | . = . + _Min_Heap_Size; 176 | . = . + _Min_Stack_Size; 177 | . = ALIGN(4); 178 | } >RAM 179 | 180 | 181 | 182 | /* Remove information from the standard libraries */ 183 | /DISCARD/ : 184 | { 185 | libc.a ( * ) 186 | libm.a ( * ) 187 | libgcc.a ( * ) 188 | } 189 | 190 | .ARM.attributes 0 : { *(.ARM.attributes) } 191 | } 192 | 193 | 194 | -------------------------------------------------------------------------------- /stm32f4xx_conf.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file TIM_TimeBase/stm32f4xx_conf.h 4 | * @author MCD Application Team 5 | * @version V1.0.0 6 | * @date 19-September-2011 7 | * @brief Library configuration file. 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 12 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 13 | * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY 14 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 15 | * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 16 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 17 | * 18 | *

© COPYRIGHT 2011 STMicroelectronics

19 | ****************************************************************************** 20 | */ 21 | 22 | /* Define to prevent recursive inclusion -------------------------------------*/ 23 | #ifndef __STM32F4xx_CONF_H 24 | #define __STM32F4xx_CONF_H 25 | 26 | #if defined (HSE_VALUE) 27 | /* Redefine the HSE value; it's equal to 8 MHz on the STM32F4-DISCOVERY Kit */ 28 | #undef HSE_VALUE 29 | #define HSE_VALUE ((uint32_t)8000000) 30 | #endif /* HSE_VALUE */ 31 | 32 | /* Includes ------------------------------------------------------------------*/ 33 | /* Uncomment the line below to enable peripheral header file inclusion */ 34 | #include "stm32f4xx_adc.h" 35 | #include "stm32f4xx_can.h" 36 | #include "stm32f4xx_crc.h" 37 | #include "stm32f4xx_cryp.h" 38 | #include "stm32f4xx_dac.h" 39 | #include "stm32f4xx_dbgmcu.h" 40 | #include "stm32f4xx_dcmi.h" 41 | #include "stm32f4xx_dma.h" 42 | #include "stm32f4xx_exti.h" 43 | #include "stm32f4xx_flash.h" 44 | #include "stm32f4xx_fsmc.h" 45 | #include "stm32f4xx_hash.h" 46 | #include "stm32f4xx_gpio.h" 47 | #include "stm32f4xx_i2c.h" 48 | #include "stm32f4xx_iwdg.h" 49 | #include "stm32f4xx_pwr.h" 50 | #include "stm32f4xx_rcc.h" 51 | #include "stm32f4xx_rng.h" 52 | #include "stm32f4xx_rtc.h" 53 | #include "stm32f4xx_sdio.h" 54 | #include "stm32f4xx_spi.h" 55 | #include "stm32f4xx_syscfg.h" 56 | #include "stm32f4xx_tim.h" 57 | #include "stm32f4xx_usart.h" 58 | #include "stm32f4xx_wwdg.h" 59 | #include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */ 60 | 61 | /* Exported types ------------------------------------------------------------*/ 62 | /* Exported constants --------------------------------------------------------*/ 63 | 64 | /* If an external clock source is used, then the value of the following define 65 | should be set to the value of the external clock source, else, if no external 66 | clock is used, keep this define commented */ 67 | /*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */ 68 | 69 | 70 | /* Uncomment the line below to expanse the "assert_param" macro in the 71 | Standard Peripheral Library drivers code */ 72 | /* #define USE_FULL_ASSERT 1 */ 73 | 74 | /* Exported macro ------------------------------------------------------------*/ 75 | #ifdef USE_FULL_ASSERT 76 | 77 | /** 78 | * @brief The assert_param macro is used for function's parameters check. 79 | * @param expr: If expr is false, it calls assert_failed function which reports 80 | * the name of the source file and the source line number of the call 81 | * that failed. If expr is true, it returns no value. 82 | * @retval None 83 | */ 84 | #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) 85 | /* Exported functions ------------------------------------------------------- */ 86 | void assert_failed(uint8_t* file, uint32_t line); 87 | #else 88 | #define assert_param(expr) ((void)0) 89 | #endif /* USE_FULL_ASSERT */ 90 | 91 | #endif /* __STM32F4xx_CONF_H */ 92 | 93 | /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ 94 | -------------------------------------------------------------------------------- /system_stm32f4xx.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file system_stm32f4xx.c 4 | * @author MCD Application Team 5 | * @version V1.0.0 6 | * @date 19-September-2011 7 | * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File. 8 | * This file contains the system clock configuration for STM32F4xx devices, 9 | * and is generated by the clock configuration tool 10 | * stm32f4xx_Clock_Configuration_V1.0.0.xls 11 | * 12 | * 1. This file provides two functions and one global variable to be called from 13 | * user application: 14 | * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier 15 | * and Divider factors, AHB/APBx prescalers and Flash settings), 16 | * depending on the configuration made in the clock xls tool. 17 | * This function is called at startup just after reset and 18 | * before branch to main program. This call is made inside 19 | * the "startup_stm32f4xx.s" file. 20 | * 21 | * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used 22 | * by the user application to setup the SysTick 23 | * timer or configure other parameters. 24 | * 25 | * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must 26 | * be called whenever the core clock is changed 27 | * during program execution. 28 | * 29 | * 2. After each device reset the HSI (16 MHz) is used as system clock source. 30 | * Then SystemInit() function is called, in "startup_stm32f4xx.s" file, to 31 | * configure the system clock before to branch to main program. 32 | * 33 | * 3. If the system clock source selected by user fails to startup, the SystemInit() 34 | * function will do nothing and HSI still used as system clock source. User can 35 | * add some code to deal with this issue inside the SetSysClock() function. 36 | * 37 | * 4. The default value of HSE crystal is set to 8 MHz, refer to "HSE_VALUE" define 38 | * in "stm32f4xx.h" file. When HSE is used as system clock source, directly or 39 | * through PLL, and you are using different crystal you have to adapt the HSE 40 | * value to your own configuration. 41 | * 42 | * 5. This file configures the system clock as follows: 43 | *============================================================================= 44 | *============================================================================= 45 | * Supported STM32F4xx device revision | Rev A 46 | *----------------------------------------------------------------------------- 47 | * System Clock source | PLL (HSE) 48 | *----------------------------------------------------------------------------- 49 | * SYSCLK(Hz) | 168000000 50 | *----------------------------------------------------------------------------- 51 | * HCLK(Hz) | 168000000 52 | *----------------------------------------------------------------------------- 53 | * AHB Prescaler | 1 54 | *----------------------------------------------------------------------------- 55 | * APB1 Prescaler | 4 56 | *----------------------------------------------------------------------------- 57 | * APB2 Prescaler | 2 58 | *----------------------------------------------------------------------------- 59 | * HSE Frequency(Hz) | 8000000 60 | *----------------------------------------------------------------------------- 61 | * PLL_M | 8 62 | *----------------------------------------------------------------------------- 63 | * PLL_N | 336 64 | *----------------------------------------------------------------------------- 65 | * PLL_P | 2 66 | *----------------------------------------------------------------------------- 67 | * PLL_Q | 7 68 | *----------------------------------------------------------------------------- 69 | * PLLI2S_N | NA 70 | *----------------------------------------------------------------------------- 71 | * PLLI2S_R | NA 72 | *----------------------------------------------------------------------------- 73 | * I2S input clock | NA 74 | *----------------------------------------------------------------------------- 75 | * VDD(V) | 3.3 76 | *----------------------------------------------------------------------------- 77 | * High Performance mode | Enabled 78 | *----------------------------------------------------------------------------- 79 | * Flash Latency(WS) | 5 80 | *----------------------------------------------------------------------------- 81 | * Prefetch Buffer | OFF 82 | *----------------------------------------------------------------------------- 83 | * Instruction cache | ON 84 | *----------------------------------------------------------------------------- 85 | * Data cache | ON 86 | *----------------------------------------------------------------------------- 87 | * Require 48MHz for USB OTG FS, | Enabled 88 | * SDIO and RNG clock | 89 | *----------------------------------------------------------------------------- 90 | *============================================================================= 91 | ****************************************************************************** 92 | * @attention 93 | * 94 | * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 95 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 96 | * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY 97 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 98 | * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 99 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 100 | * 101 | *

© COPYRIGHT 2011 STMicroelectronics

102 | ****************************************************************************** 103 | */ 104 | 105 | /** @addtogroup CMSIS 106 | * @{ 107 | */ 108 | 109 | /** @addtogroup stm32f4xx_system 110 | * @{ 111 | */ 112 | 113 | /** @addtogroup STM32F4xx_System_Private_Includes 114 | * @{ 115 | */ 116 | 117 | #include "stm32f4xx.h" 118 | 119 | /** 120 | * @} 121 | */ 122 | 123 | /** @addtogroup STM32F4xx_System_Private_TypesDefinitions 124 | * @{ 125 | */ 126 | 127 | /** 128 | * @} 129 | */ 130 | 131 | /** @addtogroup STM32F4xx_System_Private_Defines 132 | * @{ 133 | */ 134 | 135 | /*!< Uncomment the following line if you need to use external SRAM mounted 136 | on STM324xG_EVAL board as data memory */ 137 | /* #define DATA_IN_ExtSRAM */ 138 | 139 | /*!< Uncomment the following line if you need to relocate your vector Table in 140 | Internal SRAM. */ 141 | /* #define VECT_TAB_SRAM */ 142 | #define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. 143 | This value must be a multiple of 0x200. */ 144 | 145 | 146 | /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ 147 | #define PLL_M 8 148 | #define PLL_N 336 149 | 150 | /* SYSCLK = PLL_VCO / PLL_P */ 151 | #define PLL_P 2 152 | 153 | /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ 154 | #define PLL_Q 7 155 | 156 | /** 157 | * @} 158 | */ 159 | 160 | /** @addtogroup STM32F4xx_System_Private_Macros 161 | * @{ 162 | */ 163 | 164 | /** 165 | * @} 166 | */ 167 | 168 | /** @addtogroup STM32F4xx_System_Private_Variables 169 | * @{ 170 | */ 171 | 172 | uint32_t SystemCoreClock = 168000000; 173 | 174 | __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; 175 | 176 | /** 177 | * @} 178 | */ 179 | 180 | /** @addtogroup STM32F4xx_System_Private_FunctionPrototypes 181 | * @{ 182 | */ 183 | 184 | static void SetSysClock(void); 185 | #ifdef DATA_IN_ExtSRAM 186 | static void SystemInit_ExtMemCtl(void); 187 | #endif /* DATA_IN_ExtSRAM */ 188 | 189 | /** 190 | * @} 191 | */ 192 | 193 | /** @addtogroup STM32F4xx_System_Private_Functions 194 | * @{ 195 | */ 196 | 197 | /** 198 | * @brief Setup the microcontroller system 199 | * Initialize the Embedded Flash Interface, the PLL and update the 200 | * SystemFrequency variable. 201 | * @param None 202 | * @retval None 203 | */ 204 | void SystemInit(void) 205 | { 206 | /* Reset the RCC clock configuration to the default reset state ------------*/ 207 | /* Set HSION bit */ 208 | RCC->CR |= (uint32_t)0x00000001; 209 | 210 | /* Reset CFGR register */ 211 | RCC->CFGR = 0x00000000; 212 | 213 | /* Reset HSEON, CSSON and PLLON bits */ 214 | RCC->CR &= (uint32_t)0xFEF6FFFF; 215 | 216 | /* Reset PLLCFGR register */ 217 | RCC->PLLCFGR = 0x24003010; 218 | 219 | /* Reset HSEBYP bit */ 220 | RCC->CR &= (uint32_t)0xFFFBFFFF; 221 | 222 | /* Disable all interrupts */ 223 | RCC->CIR = 0x00000000; 224 | 225 | #ifdef DATA_IN_ExtSRAM 226 | SystemInit_ExtMemCtl(); 227 | #endif /* DATA_IN_ExtSRAM */ 228 | 229 | /* Configure the System clock source, PLL Multiplier and Divider factors, 230 | AHB/APBx prescalers and Flash settings ----------------------------------*/ 231 | SetSysClock(); 232 | 233 | /* Configure the Vector Table location add offset address ------------------*/ 234 | #ifdef VECT_TAB_SRAM 235 | SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ 236 | #else 237 | SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ 238 | #endif 239 | } 240 | 241 | /** 242 | * @brief Update SystemCoreClock variable according to Clock Register Values. 243 | * The SystemCoreClock variable contains the core clock (HCLK), it can 244 | * be used by the user application to setup the SysTick timer or configure 245 | * other parameters. 246 | * 247 | * @note Each time the core clock (HCLK) changes, this function must be called 248 | * to update SystemCoreClock variable value. Otherwise, any configuration 249 | * based on this variable will be incorrect. 250 | * 251 | * @note - The system frequency computed by this function is not the real 252 | * frequency in the chip. It is calculated based on the predefined 253 | * constant and the selected clock source: 254 | * 255 | * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) 256 | * 257 | * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) 258 | * 259 | * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) 260 | * or HSI_VALUE(*) multiplied/divided by the PLL factors. 261 | * 262 | * (*) HSI_VALUE is a constant defined in stm32f4xx.h file (default value 263 | * 16 MHz) but the real value may vary depending on the variations 264 | * in voltage and temperature. 265 | * 266 | * (**) HSE_VALUE is a constant defined in stm32f4xx.h file (default value 267 | * 25 MHz), user has to ensure that HSE_VALUE is same as the real 268 | * frequency of the crystal used. Otherwise, this function may 269 | * have wrong result. 270 | * 271 | * - The result of this function could be not correct when using fractional 272 | * value for HSE crystal. 273 | * 274 | * @param None 275 | * @retval None 276 | */ 277 | void SystemCoreClockUpdate(void) 278 | { 279 | uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2; 280 | 281 | /* Get SYSCLK source -------------------------------------------------------*/ 282 | tmp = RCC->CFGR & RCC_CFGR_SWS; 283 | 284 | switch (tmp) 285 | { 286 | case 0x00: /* HSI used as system clock source */ 287 | SystemCoreClock = HSI_VALUE; 288 | break; 289 | case 0x04: /* HSE used as system clock source */ 290 | SystemCoreClock = HSE_VALUE; 291 | break; 292 | case 0x08: /* PLL used as system clock source */ 293 | 294 | /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N 295 | SYSCLK = PLL_VCO / PLL_P 296 | */ 297 | pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22; 298 | pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM; 299 | 300 | if (pllsource != 0) 301 | { 302 | /* HSE used as PLL clock source */ 303 | pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); 304 | } 305 | else 306 | { 307 | /* HSI used as PLL clock source */ 308 | pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); 309 | } 310 | 311 | pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2; 312 | SystemCoreClock = pllvco/pllp; 313 | break; 314 | default: 315 | SystemCoreClock = HSI_VALUE; 316 | break; 317 | } 318 | /* Compute HCLK frequency --------------------------------------------------*/ 319 | /* Get HCLK prescaler */ 320 | tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; 321 | /* HCLK frequency */ 322 | SystemCoreClock >>= tmp; 323 | } 324 | 325 | /** 326 | * @brief Configures the System clock source, PLL Multiplier and Divider factors, 327 | * AHB/APBx prescalers and Flash settings 328 | * @Note This function should be called only once the RCC clock configuration 329 | * is reset to the default reset state (done in SystemInit() function). 330 | * @param None 331 | * @retval None 332 | */ 333 | static void SetSysClock(void) 334 | { 335 | /******************************************************************************/ 336 | /* PLL (clocked by HSE) used as System clock source */ 337 | /******************************************************************************/ 338 | __IO uint32_t StartUpCounter = 0, HSEStatus = 0; 339 | 340 | /* Enable HSE */ 341 | RCC->CR |= ((uint32_t)RCC_CR_HSEON); 342 | 343 | /* Wait till HSE is ready and if Time out is reached exit */ 344 | do 345 | { 346 | HSEStatus = RCC->CR & RCC_CR_HSERDY; 347 | StartUpCounter++; 348 | } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); 349 | 350 | if ((RCC->CR & RCC_CR_HSERDY) != RESET) 351 | { 352 | HSEStatus = (uint32_t)0x01; 353 | } 354 | else 355 | { 356 | HSEStatus = (uint32_t)0x00; 357 | } 358 | 359 | if (HSEStatus == (uint32_t)0x01) 360 | { 361 | /* Enable high performance mode, System frequency up to 168 MHz */ 362 | RCC->APB1ENR |= RCC_APB1ENR_PWREN; 363 | PWR->CR |= PWR_CR_PMODE; 364 | 365 | /* HCLK = SYSCLK / 1*/ 366 | RCC->CFGR |= RCC_CFGR_HPRE_DIV1; 367 | 368 | /* PCLK2 = HCLK / 2*/ 369 | RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; 370 | 371 | /* PCLK1 = HCLK / 4*/ 372 | RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; 373 | 374 | /* Configure the main PLL */ 375 | RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | 376 | (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); 377 | 378 | /* Enable the main PLL */ 379 | RCC->CR |= RCC_CR_PLLON; 380 | 381 | /* Wait till the main PLL is ready */ 382 | while((RCC->CR & RCC_CR_PLLRDY) == 0) 383 | { 384 | } 385 | 386 | /* Configure Flash prefetch, Instruction cache, Data cache and wait state */ 387 | FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; 388 | 389 | /* Select the main PLL as system clock source */ 390 | RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); 391 | RCC->CFGR |= RCC_CFGR_SW_PLL; 392 | 393 | /* Wait till the main PLL is used as system clock source */ 394 | while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); 395 | //{ 396 | //} 397 | } 398 | else 399 | { /* If HSE fails to start-up, the application will have wrong clock 400 | configuration. User can add here some code to deal with this error */ 401 | } 402 | 403 | } 404 | 405 | /** 406 | * @brief Setup the external memory controller. Called in startup_stm32f4xx.s 407 | * before jump to __main 408 | * @param None 409 | * @retval None 410 | */ 411 | #ifdef DATA_IN_ExtSRAM 412 | /** 413 | * @brief Setup the external memory controller. 414 | * Called in startup_stm32f4xx.s before jump to main. 415 | * This function configures the external SRAM mounted on STM324xG_EVAL board 416 | * This SRAM will be used as program data memory (including heap and stack). 417 | * @param None 418 | * @retval None 419 | */ 420 | void SystemInit_ExtMemCtl(void) 421 | { 422 | /*-- GPIOs Configuration -----------------------------------------------------*/ 423 | /* 424 | +-------------------+--------------------+------------------+------------------+ 425 | + SRAM pins assignment + 426 | +-------------------+--------------------+------------------+------------------+ 427 | | PD0 <-> FSMC_D2 | PE0 <-> FSMC_NBL0 | PF0 <-> FSMC_A0 | PG0 <-> FSMC_A10 | 428 | | PD1 <-> FSMC_D3 | PE1 <-> FSMC_NBL1 | PF1 <-> FSMC_A1 | PG1 <-> FSMC_A11 | 429 | | PD4 <-> FSMC_NOE | PE3 <-> FSMC_A19 | PF2 <-> FSMC_A2 | PG2 <-> FSMC_A12 | 430 | | PD5 <-> FSMC_NWE | PE4 <-> FSMC_A20 | PF3 <-> FSMC_A3 | PG3 <-> FSMC_A13 | 431 | | PD8 <-> FSMC_D13 | PE7 <-> FSMC_D4 | PF4 <-> FSMC_A4 | PG4 <-> FSMC_A14 | 432 | | PD9 <-> FSMC_D14 | PE8 <-> FSMC_D5 | PF5 <-> FSMC_A5 | PG5 <-> FSMC_A15 | 433 | | PD10 <-> FSMC_D15 | PE9 <-> FSMC_D6 | PF12 <-> FSMC_A6 | PG9 <-> FSMC_NE2 | 434 | | PD11 <-> FSMC_A16 | PE10 <-> FSMC_D7 | PF13 <-> FSMC_A7 |------------------+ 435 | | PD12 <-> FSMC_A17 | PE11 <-> FSMC_D8 | PF14 <-> FSMC_A8 | 436 | | PD13 <-> FSMC_A18 | PE12 <-> FSMC_D9 | PF15 <-> FSMC_A9 | 437 | | PD14 <-> FSMC_D0 | PE13 <-> FSMC_D10 |------------------+ 438 | | PD15 <-> FSMC_D1 | PE14 <-> FSMC_D11 | 439 | | | PE15 <-> FSMC_D12 | 440 | +-------------------+--------------------+ 441 | */ 442 | /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */ 443 | RCC->AHB1ENR = 0x00000078; 444 | 445 | /* Connect PDx pins to FSMC Alternate function */ 446 | GPIOD->AFR[0] = 0x00cc00cc; 447 | GPIOD->AFR[1] = 0xcc0ccccc; 448 | /* Configure PDx pins in Alternate function mode */ 449 | GPIOD->MODER = 0xaaaa0a0a; 450 | /* Configure PDx pins speed to 100 MHz */ 451 | GPIOD->OSPEEDR = 0xffff0f0f; 452 | /* Configure PDx pins Output type to push-pull */ 453 | GPIOD->OTYPER = 0x00000000; 454 | /* No pull-up, pull-down for PDx pins */ 455 | GPIOD->PUPDR = 0x00000000; 456 | 457 | /* Connect PEx pins to FSMC Alternate function */ 458 | GPIOE->AFR[0] = 0xc00cc0cc; 459 | GPIOE->AFR[1] = 0xcccccccc; 460 | /* Configure PEx pins in Alternate function mode */ 461 | GPIOE->MODER = 0xaaaa828a; 462 | /* Configure PEx pins speed to 100 MHz */ 463 | GPIOE->OSPEEDR = 0xffffc3cf; 464 | /* Configure PEx pins Output type to push-pull */ 465 | GPIOE->OTYPER = 0x00000000; 466 | /* No pull-up, pull-down for PEx pins */ 467 | GPIOE->PUPDR = 0x00000000; 468 | 469 | /* Connect PFx pins to FSMC Alternate function */ 470 | GPIOF->AFR[0] = 0x00cccccc; 471 | GPIOF->AFR[1] = 0xcccc0000; 472 | /* Configure PFx pins in Alternate function mode */ 473 | GPIOF->MODER = 0xaa000aaa; 474 | /* Configure PFx pins speed to 100 MHz */ 475 | GPIOF->OSPEEDR = 0xff000fff; 476 | /* Configure PFx pins Output type to push-pull */ 477 | GPIOF->OTYPER = 0x00000000; 478 | /* No pull-up, pull-down for PFx pins */ 479 | GPIOF->PUPDR = 0x00000000; 480 | 481 | /* Connect PGx pins to FSMC Alternate function */ 482 | GPIOG->AFR[0] = 0x00cccccc; 483 | GPIOG->AFR[1] = 0x000000c0; 484 | /* Configure PGx pins in Alternate function mode */ 485 | GPIOG->MODER = 0x00080aaa; 486 | /* Configure PGx pins speed to 100 MHz */ 487 | GPIOG->OSPEEDR = 0x000c0fff; 488 | /* Configure PGx pins Output type to push-pull */ 489 | GPIOG->OTYPER = 0x00000000; 490 | /* No pull-up, pull-down for PGx pins */ 491 | GPIOG->PUPDR = 0x00000000; 492 | 493 | /*-- FSMC Configuration ------------------------------------------------------*/ 494 | /* Enable the FSMC interface clock */ 495 | RCC->AHB3ENR = 0x00000001; 496 | 497 | /* Configure and enable Bank1_SRAM2 */ 498 | FSMC_Bank1->BTCR[2] = 0x00001015; 499 | FSMC_Bank1->BTCR[3] = 0x00010603;//0x00010400; 500 | FSMC_Bank1E->BWTR[2] = 0x0fffffff; 501 | /* 502 | Bank1_SRAM2 is configured as follow: 503 | 504 | p.FSMC_AddressSetupTime = 3;//0; 505 | p.FSMC_AddressHoldTime = 0; 506 | p.FSMC_DataSetupTime = 6;//4; 507 | p.FSMC_BusTurnAroundDuration = 1; 508 | p.FSMC_CLKDivision = 0; 509 | p.FSMC_DataLatency = 0; 510 | p.FSMC_AccessMode = FSMC_AccessMode_A; 511 | 512 | FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM2; 513 | FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; 514 | FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM; 515 | FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; 516 | FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable; 517 | FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable; 518 | FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low; 519 | FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; 520 | FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState; 521 | FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; 522 | FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable; 523 | FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; 524 | FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable; 525 | FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p; 526 | FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p; 527 | */ 528 | 529 | } 530 | #endif /* DATA_IN_ExtSRAM */ 531 | 532 | 533 | /** 534 | * @} 535 | */ 536 | 537 | /** 538 | * @} 539 | */ 540 | 541 | /** 542 | * @} 543 | */ 544 | /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ 545 | 546 | -------------------------------------------------------------------------------- /transfer.sh: -------------------------------------------------------------------------------- 1 | sudo dfu-util -v -d 0483:df11 -a 0 -s 0x08000000 -D electron-rom-emulator.bin 2 | --------------------------------------------------------------------------------