Compare commits

...

184 Commits

Author SHA1 Message Date
King Kévin 9d7e4940e9 application: add eMrker read out 2020-03-01 23:22:49 +01:00
King Kévin 0c5f5e8c2d usb_fusb302: add checksum calculation 2020-03-01 23:21:07 +01:00
King Kévin d17363b680 usb_fusb302: minor, check input 2020-03-01 23:20:36 +01:00
King Kévin 67569476dc usb_fusb302: remove unnecessary VCONN toggling (only the waiting time is required) 2020-03-01 23:20:11 +01:00
King Kévin 39f6ab9821 usb_fusb302: add function to set PD line, send reset, send identity request, and read incoming data 2020-03-01 14:13:39 +01:00
King Kévin 5b700ba53b usb_fusb302: add disconnect function 2020-03-01 14:12:16 +01:00
King Kévin f55a4a58d1 application: better description in Cplug action 2020-02-28 17:39:50 +01:00
King Kévin 4d8f1d537a application: add USB-C ressitor using FUSB302 to in Cplug action 2020-02-28 17:14:28 +01:00
King Kévin 93af648943 usb_fusb302: add library for FUSB302 USB-C controller 2020-02-28 16:40:44 +01:00
King Kévin b5bdfd9855 Rakefile: include USB PD library 2020-02-27 20:27:08 +01:00
King Kévin 83432a483e remove unused USB PD function definitions 2020-02-27 20:26:54 +01:00
King Kévin 24ee293a9b import chromium OS USB PD definitions 2020-02-27 20:26:37 +01:00
King Kévin 50f27af934 lcd_hd44780: add set_led 2020-02-27 20:24:15 +01:00
King Kévin 51bbed144c oled_ssd1306: fix writing to display 2020-02-27 19:43:14 +01:00
King Kévin 68f9577452 application: check is oled setup is successful 2020-02-27 19:41:55 +01:00
King Kévin c4f011c8b8 oled_test: return if setup is successful 2020-02-27 19:40:52 +01:00
King Kévin dcd773b9d8 global: remove definitions for other boards not used for this project 2020-02-27 17:15:15 +01:00
King Kévin 33ec1bcd26 usb_cables: add usb-c signal shunt 2020-02-27 16:49:35 +01:00
King Kévin d43b098fbf application: minor, make cable action more readable 2020-02-27 16:49:35 +01:00
King Kévin cd9f4e12de application: fix cables_issues_nb 2020-02-27 16:49:35 +01:00
King Kévin a682dc985a application: fix print output 2020-02-27 16:49:35 +01:00
King Kévin caacafb686 usb_cables: improve power connection test, but reduce pattern length 2020-02-27 16:49:35 +01:00
King Kévin 6d77a2b629 usb_cables: fix Rd/Rp 2020-02-27 16:49:35 +01:00
King Kévin b96ca1b3de usb_cables: don't treat CC as power since false positive load check prevent it from being tested 2020-02-27 16:49:35 +01:00
King Kévin e7c315c881 usb_cables: rename C-pin n/p to -/+ 2020-02-27 16:49:35 +01:00
King Kévin 493d12590d usb_cables: fix CB cable definition 2020-02-27 16:49:35 +01:00
King Kévin ece4052425 application: fix connection intra action 2020-02-27 16:49:35 +01:00
King Kévin 9b1cf02a50 usb_cable: fix C to xB cable definition 2020-02-27 16:49:35 +01:00
King Kévin b4557825c5 usb_cables: fix cub3 cable definition 2020-02-27 16:49:35 +01:00
King Kévin 498fabf8a1 usb_cable: fix AC3 cable definition 2020-02-27 16:49:35 +01:00
King Kévin 4fa37f4957 application: fix backup writing 2020-02-27 16:49:35 +01:00
King Kévin 73bbb7974d application: display connection details when single cable is tested 2020-02-27 16:49:35 +01:00
King Kévin ac3975c1b2 application: show connection details 2020-02-27 16:49:35 +01:00
King Kévin 4067dc090c usb_cable: fix C-C FF cable definition 2020-02-27 16:49:35 +01:00
King Kévin 943d4ecb35 usb_cable: fix and improve pin connection test 2020-02-27 16:49:35 +01:00
King Kévin 69d2f047c8 application: print connection details 2020-02-27 16:49:35 +01:00
King Kévin b7b9de846d application: remove duplicate function 2020-02-27 16:49:35 +01:00
King Kévin 95646cd89b usb_cables: return pin interconnection details 2020-02-27 16:49:35 +01:00
King Kévin e84a481669 usb_cables: improve pin test and make it more simpler 2020-02-27 16:49:35 +01:00
King Kévin 7dd50762b8 application: add action to test C plugs 2020-02-27 16:49:35 +01:00
King Kévin 4bf22ca1e8 application: display cable variant when finding cable 2020-02-27 16:49:35 +01:00
King Kévin 6704665487 application: display cable variant when testing cable 2020-02-27 16:49:35 +01:00
King Kévin 501af16820 usb_cable: add cable variant description 2020-02-27 16:49:35 +01:00
King Kévin 23b8e7cd15 application: fix test action 2020-02-27 16:49:35 +01:00
King Kévin 9795aad753 usb_cable: add cable identifiers 2020-02-27 16:49:35 +01:00
King Kévin 3c019008dc usb_cables: add connector identifiers 2020-02-27 16:49:35 +01:00
King Kévin ca741e5e68 application: show cable shot name on LCD 2020-02-27 16:49:35 +01:00
King Kévin 6935a5d89d usb_cables: add cable short names 2020-02-27 16:49:35 +01:00
King Kévin bfcb54c687 usb_cables: add battery charger cables 2020-02-27 16:49:35 +01:00
King Kévin 5434633fb3 application: show additional detection on OLED 2020-02-27 16:49:35 +01:00
King Kévin e1a3ebb5ef OLED: increas text font size 2020-02-27 16:49:35 +01:00
King Kévin a2f83e87b3 USB: ensure USB D+ pullup is handled by USB lib 2020-02-27 16:49:35 +01:00
King Kévin 2fb4274ebc oled_text: remove blinking on OLED update 2020-02-27 16:49:15 +01:00
King Kévin ae951d8c12 application: fix OLED text when disconnecting cable 2020-02-27 16:49:15 +01:00
King Kévin e1802fcc2f application: display text on OLED 2020-02-27 16:49:15 +01:00
King Kévin da0a440e0e oled_text: add library to display text on OLED 2020-02-27 16:49:15 +01:00
King Kévin cce117ce70 oled_ssd1306: adjust conf to project 2020-02-27 16:49:15 +01:00
King Kévin 35c708dbd1 application: get and print optional connections 2020-02-27 16:49:15 +01:00
King Kévin 3ce2418f18 application: fix cable detection 2020-02-27 16:49:15 +01:00
King Kévin d7223dd518 application: add ground check to find cable 2020-02-27 16:49:15 +01:00
King Kévin eaed513dec usb_cables: fix ground check 2020-02-27 16:49:15 +01:00
King Kévin 43df1a9b33 usb_cables: add optional pin pairs 2020-02-27 16:49:15 +01:00
King Kévin cbd67810f4 usb_cables: also generate optional pin pairs definittions 2020-02-27 16:49:15 +01:00
King Kévin 3bdad80428 usb_cable: minor, fix formatting 2020-02-27 16:49:15 +01:00
King Kévin 3222716361 usb_cables: add return to ground check 2020-02-27 16:49:15 +01:00
King Kévin b3aab7616b usb_cables: add optional pin pars field 2020-02-27 16:49:15 +01:00
King Kévin f80f30eb1e application: add fast ground scan 2020-02-27 16:49:13 +01:00
King Kévin bdb5b740db usb_cables: remove print from ground check 2020-02-27 16:48:16 +01:00
King Kévin c66e19f714 usb_cable: use short names on LCD 2020-02-27 16:48:16 +01:00
King Kévin 18ec94f0ba usb_cable: add short names 2020-02-27 16:48:16 +01:00
King Kévin 6b391af92a application: print check result on LCD 2020-02-27 16:48:14 +01:00
King Kévin a58df32707 application: minor, redability 2020-02-27 16:46:09 +01:00
King Kévin d27eff0882 application: small output fix 2020-02-27 16:46:09 +01:00
King Kévin c61cdd2d82 application: minor, redability 2020-02-27 16:46:09 +01:00
King Kévin 07546dc000 bootloader: set DFU force pin to SWDIO instead of SWCLK to allow debudding 2020-02-27 16:46:06 +01:00
King Kévin e1a4a71c90 application: remove now automatic find lcd action 2020-02-27 16:45:26 +01:00
King Kévin 9339db28b5 application: add periodic cable test 2020-02-27 16:45:26 +01:00
King Kévin 42afe7e7b8 application: small fixes 2020-02-27 16:45:26 +01:00
King Kévin 66529b28af application: add load test to find action 2020-02-27 16:45:26 +01:00
King Kévin 6b228c18af application: add load check to intra connection test 2020-02-27 16:45:26 +01:00
King Kévin 4fd46c1133 usb_cables: minor, function rename 2020-02-27 16:45:26 +01:00
King Kévin 7ee2d7098c usb_cables: minor, function rename 2020-02-27 16:45:26 +01:00
King Kévin c19cbe07d1 usb_cables: minor, function rename 2020-02-27 16:45:26 +01:00
King Kévin fad74acd9e usb_cables: minor, function rename 2020-02-27 16:45:26 +01:00
King Kévin e85cdb52d0 application: minor, restructure 2020-02-27 16:45:26 +01:00
King Kévin 439472730d global: remove debug 2020-02-27 16:45:26 +01:00
King Kévin 3ba1728118 application: minor, faster initial output 2020-02-27 16:45:26 +01:00
King Kévin 3da74a359b application: minor, fix doc 2020-02-27 16:45:26 +01:00
King Kévin 27d97f565c application: add mechanism to remain in standby 2020-02-27 16:45:26 +01:00
King Kévin 34f6b52969 bootloader: use magic value in RAM instead of peripheral 2020-02-27 16:45:26 +01:00
King Kévin b4bf18c316 application: split find into individual functions 2020-02-27 16:45:26 +01:00
King Kévin 1e808f66b2 application: add auto-shutdown 2020-02-27 16:45:26 +01:00
King Kévin 2e9ad46a76 remove LED, and add display control including USB D+ pull-up 2020-02-27 16:45:26 +01:00
King Kévin dd509c3d8f application: rewrite find action and make faster 2020-02-27 16:45:26 +01:00
King Kévin 28024ae960 usb_cables: remove superseeded functions 2020-02-27 16:45:26 +01:00
King Kévin 84d679c3ef usb_cables: minor, rename function 2020-02-27 16:45:26 +01:00
King Kévin 0cb628deb2 application: minor, fix doc 2020-02-27 16:45:26 +01:00
King Kévin 30b7e9c4ba application: extend connection action 2020-02-27 16:45:26 +01:00
King Kévin 788a36b175 usb_cables: add options to connections check 2020-02-27 16:45:26 +01:00
King Kévin b0441f40c5 application: add action to test all connections 2020-02-27 16:45:26 +01:00
King Kévin 151b7f1c9c usb_cables: add function to test and return all connections 2020-02-27 16:45:26 +01:00
King Kévin fc6a7a6d3d usb_cables: add function to get connector from pin 2020-02-27 16:45:26 +01:00
King Kévin 43046dee48 application: minor, remove debug output 2020-02-27 16:45:26 +01:00
King Kévin a7a2302376 usb_cables: minor, fix typo 2020-02-27 16:45:26 +01:00
King Kévin 2e09990f2b usb_cables: add function to float all USB pins 2020-02-27 16:45:26 +01:00
King Kévin 25b8a59663 application: fix test connectors 2020-02-27 16:45:26 +01:00
King Kévin fca92ed6c6 usb_cables: connectors have a variant instead of host property 2020-02-27 16:45:26 +01:00
King Kévin 3cb4b3689e application: add LCD initialisation 2020-02-27 16:45:23 +01:00
King Kévin 88e13ccd67 application: improve pin action output 2020-02-27 16:44:10 +01:00
King Kévin ba50a0ec84 application: add load test to find action 2020-02-27 16:44:10 +01:00
King Kévin 74eeb7d51e usb_cables: fix cc pins 2020-02-27 16:44:10 +01:00
King Kévin b00916288e usb_cables: fix cc cables 2020-02-27 16:44:10 +01:00
King Kévin 6f7097c149 usb_cables: rename signals 2020-02-27 16:44:10 +01:00
King Kévin 2f00ac5a67 usb_cables: add aamb2 cables 2020-02-27 16:44:10 +01:00
King Kévin 9dd5bb4b5e usb_cables: add aab2 cables 2020-02-27 16:44:10 +01:00
King Kévin d9f3183910 usb_cables: rename cables 2020-02-27 16:44:10 +01:00
King Kévin 164590746d usb_cables: add C-C full featured cables 2020-02-27 16:44:10 +01:00
King Kévin 1db45d7bdb usb_cables: add cc2 cables 2020-02-27 16:44:10 +01:00
King Kévin f206343b49 usb_cables: rename *3g2 cables to *3 2020-02-27 16:44:10 +01:00
King Kévin 9a58ad4101 usb_cables: add cmicrob3g2 cables 2020-02-27 16:44:10 +01:00
King Kévin 6762462ec6 usb_cables: add cmicrob2 cables 2020-02-27 16:44:10 +01:00
King Kévin a632c11c67 usb_cables: add cminib2 cables 2020-02-27 16:44:10 +01:00
King Kévin 8d92c37e7e usb_cables: add cb3g2 cables 2020-02-27 16:44:10 +01:00
King Kévin 85bdcf1309 usb_cables: fix cb2 cables comments 2020-02-27 16:44:10 +01:00
King Kévin ab47587a15 usb_cables: add cb2 cables 2020-02-27 16:44:10 +01:00
King Kévin 34f24a5ce3 usb_cables: add ac3g2 variants 2020-02-27 16:44:10 +01:00
King Kévin 0fde15e6ba usb_cables: don't drive shield pins 2020-02-27 16:44:10 +01:00
King Kévin 060704a7d9 usb_cables: fix AC3G2 definition 2020-02-27 16:44:10 +01:00
King Kévin be00f205ac usb_cables: add all AC2 cable variants 2020-02-27 16:44:10 +01:00
King Kévin 26dc7d528b usb_cables: use generated cable defintions 2020-02-27 16:44:10 +01:00
King Kévin aa6bb0ace7 usb_cables: fix generator script 2020-02-27 16:44:10 +01:00
King Kévin f31fd6052d usb_cable: add script to generate derivative cable definitions 2020-02-27 16:44:10 +01:00
King Kévin 33458c8a13 usb_cables: start using autogenerated derivative cables 2020-02-27 16:44:10 +01:00
King Kévin 6749a42d12 usb_cable: fix c shunt cable 2020-02-27 16:44:10 +01:00
King Kévin ff23100dfa usb_cables: use index for pins to save space 2020-02-27 16:44:10 +01:00
King Kévin 549f1c992f usb_cables: remove duplicate output parameter 2020-02-27 16:44:10 +01:00
King Kévin 2d5a2b7f4f application: pin action shows atual floating value 2020-02-27 16:44:10 +01:00
King Kévin 4aec3da96c usb_cables: add option to print cable connection mismatches 2020-02-27 16:44:10 +01:00
King Kévin 84db14e71c usb_cables: correct and add C cables 2020-02-27 16:44:10 +01:00
King Kévin 20e02c91ad application: improve cable find action 2020-02-27 16:44:10 +01:00
King Kévin 8b8dfa5141 usb_cable: improve find connection test speed 2020-02-27 16:44:10 +01:00
King Kévin b9da72b3a7 usb_cables: add USB-C cable 2020-02-27 16:44:10 +01:00
King Kévin f7dce91bb8 usb_cables: minor, add doc 2020-02-27 16:44:10 +01:00
King Kévin 4262e90792 usb_cables: improve mechanism to find if pins are conencted 2020-02-27 16:44:10 +01:00
King Kévin e4b8be4e5a usb_cdcacm: increase output buffer size for more smooth output 2020-02-27 16:44:10 +01:00
King Kévin dfa24b30a8 application: add load check and update cable check 2020-02-27 16:44:10 +01:00
King Kévin f93644d127 usb_cables: add load check function
this needed to add information about the pin type.
also pins are now considered as connected if any direction or
level works.
thus there are no errors anymore when testing cables.
power with ground pins are not tested anymore because optional
loads are causing false positives (regarding if pins are
connected).
2020-02-27 16:44:10 +01:00
King Kévin 76d8a23281 usb_cables: minor, make more readable 2020-02-27 16:44:10 +01:00
King Kévin 4735911444 usb_cables: add faster inter-connector test using ground 2020-02-27 16:44:10 +01:00
King Kévin 84c70a61d1 usb_cables: improve inter-connector test 2020-02-27 16:44:10 +01:00
King Kévin 9bcd7c94f0 usb_cables: minor, rename USB-C +/- to p/n 2020-02-27 16:44:10 +01:00
King Kévin 2513c89fa9 application: add USB-C shunt to test list 2020-02-27 16:44:10 +01:00
King Kévin a604531eae usb_cables: minor, document cable connections 2020-02-27 16:44:10 +01:00
King Kévin f310a453a7 usb_cables: add USB-C shunt cable definitions 2020-02-27 16:44:10 +01:00
King Kévin 946ba2e243 usb_cables: fix inter-connector output 2020-02-27 16:44:10 +01:00
King Kévin f69ff24764 usb_cables: fix USB mini-B pinout 2020-02-27 16:44:10 +01:00
King Kévin 5673df323e usb_cables: fix USB-C D+2/D-2 pinout 2020-02-27 16:44:10 +01:00
King Kévin e2a3a60d3a application: add board test action 2020-02-27 16:44:10 +01:00
King Kévin c0bd9291cc application: fix cable finder 2020-02-27 16:44:10 +01:00
King Kévin 8519698af6 application: improve cable check output 2020-02-27 16:44:10 +01:00
King Kévin 710a2f8218 application: fix string output conditions 2020-02-27 16:44:10 +01:00
King Kévin 2fe895d964 usb_cables: allow NULL arguments 2020-02-27 16:44:10 +01:00
King Kévin 619954239a usb_cables: fix output string 2020-02-27 16:44:10 +01:00
King Kévin b1d0262699 usb_cables: give more time for signal to settle for more stable connection checks 2020-02-27 16:44:10 +01:00
King Kévin 990241c0c8 usb_cables: fix USB-A 3.0 pinout and names 2020-02-27 16:44:10 +01:00
King Kévin a00bd3fd24 usb_cdcacm: set product string 2020-02-27 16:44:10 +01:00
King Kévin 6b517bc4f2 application: fix and improvement pin action 2020-02-27 16:44:10 +01:00
King Kévin 99fc82227a usb_cables: add settling time before reading GPIO 2020-02-27 16:44:10 +01:00
King Kévin 29e0ec99df application: add action to get/set individual USB pins 2020-02-27 16:44:10 +01:00
King Kévin 57de92d362 application: fix, peripheral clocks must be enable individually 2020-02-27 16:44:10 +01:00
King Kévin 3e37211c90 update linker script to STM32F103xC memory sizes 2020-02-27 16:43:57 +01:00
King Kévin 2538ee6683 usb_cables: add miniB and microB cable definitions 2020-02-27 16:41:18 +01:00
King Kévin b16621314e usb_cables: add cable definitions 2020-02-27 16:41:18 +01:00
King Kévin 3624ca410f usb_cables: use more pointers to save space (and add cable definitions) 2020-02-27 16:41:18 +01:00
King Kévin 4f4a16b9db application: add individual USB connector and cable test commands 2020-02-27 16:41:18 +01:00
King Kévin a5a5b06926 usb_cables: add output to intra and inter connection check 2020-02-27 16:41:18 +01:00
King Kévin 871153de51 usb_cables: fix cable checker return value 2020-02-27 16:41:18 +01:00
King Kévin 84035eaca7 usb_cables: add and use common method to test connection between two pins 2020-02-27 16:41:18 +01:00
King Kévin 99515e579f application: use caps for system actions 2020-02-27 16:41:18 +01:00
King Kévin 5a5543ae53 add test action to test USB cables 2020-02-27 16:41:18 +01:00
King Kévin 9750148e86 application: add USB cables library 2020-02-27 16:41:16 +01:00
King Kévin 5cf6f20319 usb_cables: add definitions of USB pin, connectors, (some) cables, and utilities to test connections 2020-02-27 16:39:57 +01:00
King Kévin 5e970a55b0 remove unused libraries 2020-02-27 16:39:55 +01:00
King Kévin e70edfb77e define LED and DFU board specific pins and remove unused definitions 2020-02-27 16:39:03 +01:00
68 changed files with 11608 additions and 8481 deletions

View File

@ -15,7 +15,7 @@ FIRMWARES = [BOOTLOADER, APPLICATION]
# which development board is used
# supported are: SYSTEM_BOARD, MAPLE_MINI, BLUE_PILL, BLACK_PILL, CORE_BOARD, STLINKV2, BLASTER, BUSVOODOO
BOARD = ENV["BOARD"] || "CORE_BOARD"
BOARD = ENV["BOARD"] || "USB_CABLE_TESTER"
# libopencm3 definitions
LIBOPENCM3_DIR = "libopencm3"
@ -27,6 +27,9 @@ STM32F1_LIB = "opencm3_stm32f1"
# source code used by the firmware
SRC_DIRS = [".", "lib"]
# additional include libraries
INC_DIRS = ["usb_pd"]
# cross-compiler environment
PREFIX = ENV["PREFIX"] || "arm-none-eabi"
CC = PREFIX+"-gcc"
@ -44,8 +47,8 @@ cflags = [ENV["CFLAGS"]]
cflags << "-Os"
# add debug symbols (remove for smaller release)
cflags << "-ggdb"
# use C99 (supported by most an sufficient)
cflags << "-std=c99"
# C11 is required by the USB PD library for anonymous structs
cflags << "-std=c11"
# have strict warning (for better code)
cflags << "-Wpedantic -Wall -Werror -Wundef -Wextra -Wshadow -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes -Wstrict-overflow=5"
# add options for better code optimization
@ -56,6 +59,8 @@ cflags << "-fshort-enums"
cflags << "-ffreestanding"
# include own libraries
cflags += SRC_DIRS.collect {|srd_dir| "-I #{srd_dir}"}
# additional includes
cflags += INC_DIRS.collect {|inc_dir| "-I #{inc_dir}"}
# include libopencm3 library
cflags << "-I #{LIBOPENCM3_INC}"
# add defines for micro-controller and board
@ -184,7 +189,7 @@ end
# SWD/JTAG adapter used
# supported are : STLINKV2 (ST-Link V2), BMP (Black Magic Probe)
SWD_ADAPTER = ENV["SWD_ADAPTER"] || "BMP"
SWD_ADAPTER = ENV["SWD_ADAPTER"] || "STLINKV2"
# openOCD path to control the adapter
OOCD = ENV["OOCD"] || "openocd"
# openOCD adapted name

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,6 @@
/* linker script for application running on STM32F103x8 micro-controller
* the STM32F103x8 has 64 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000
* the STM32F103xB has 128 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000
* STM32F103x8 most often have if fact 128 KB, instead of the specified and advertised 64 KB, like the STM32F103xB
* you can define the desired flash size here.
/* linker script for application running on STM32F103xC micro-controller
* the STM32F103xC has 256 KB of flash starting at 0x0800 0000, and 64 KB of RAM starting at 0x2000 0000
* STM32F103xC might have if fact 512 KB instead of the specified and advertised 256 KB
* the USB DFU bootloader will take the first 8 KB of flash, followed by the application
* the first 4 bytes of the RAM is reserved for the DFU magic word (DFU! to start DFU bootloader)
*/
@ -10,8 +8,8 @@
/* define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000 + 8K, LENGTH = 64K - 8K
ram (rwx) : ORIGIN = 0x20000000 + 4, LENGTH = 20K - 4
rom (rx) : ORIGIN = 0x08000000 + 8K, LENGTH = 256K - 8K
ram (rwx) : ORIGIN = 0x20000000 + 4, LENGTH = 64K - 4
}
PROVIDE(__application_beginning = ORIGIN(rom));
/* if you want the firmware to use the flash size advertised by the micro-controller itself, use the following:

View File

@ -75,6 +75,7 @@ void main(void)
dfu_force = true; // DFU mode forced
}
#endif // defined(DFU_FORCE_PIN)
gpio_primary_remap(AFIO_MAPR_SWJ_CFG_FULL_SWJ, 0); // re-enable full SWJ
}
// start application if valid

View File

@ -1,8 +1,6 @@
/* linker script for application running on STM32F103x8 micro-controller
* the STM32F103x8 has 64 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000
* the STM32F103xB has 128 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000
* STM32F103x8 most often have if fact 128 KB, instead of the specified and advertised 64 KB, like the STM32F103xB
* you can define the desired flash size here.
/* linker script for application running on STM32F103xC micro-controller
* the STM32F103xC has 256 KB of flash starting at 0x0800 0000, and 64 KB of RAM starting at 0x2000 0000
* STM32F103xC might have 512 KB instead of the specified and advertised 256 KB
* the USB DFU bootloader will take the first 8 KB of flash, followed by the application
* the first 4 bytes of the RAM is reserved for the DFU magic word (DFU! to start DFU bootloader)
*/
@ -11,7 +9,7 @@
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 8K
ram (rwx) : ORIGIN = 0x20000000 + 4, LENGTH = 20K - 4
ram (rwx) : ORIGIN = 0x20000000 + 4, LENGTH = 64K - 4
}
PROVIDE(__application_beginning = ORIGIN(rom) + LENGTH(rom));
/* if you want the firmware to use the flash size advertised by the micro-controller itself, use the following:

View File

@ -32,7 +32,6 @@
#include "global.h" // common methods
volatile bool button_flag = false;
volatile bool user_input_available = false;
static volatile uint8_t user_input_buffer[64] = {0}; /**< ring buffer for received data */
@ -67,9 +66,6 @@ char* b2s(uint64_t binary, uint8_t rjust)
inline void led_on(void)
{
#if defined(LED_PIN)
#if defined(BUSVOODOO)
gpio_set_mode(GPIO_PORT(LED_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(LED_PIN)); // set LED pin push-pull
#endif // BUSVOODOO
#if defined(LED_ON) && LED_ON
gpio_set(GPIO_PORT(LED_PIN), GPIO_PIN(LED_PIN));
#else
@ -82,14 +78,10 @@ inline void led_on(void)
inline void led_off(void)
{
#if defined(LED_PIN)
#if defined(BUSVOODOO)
gpio_set_mode(GPIO_PORT(LED_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LED_PIN)); // set LED pin to floating to disable LEDs
#else
#if defined(LED_ON) && LED_ON
gpio_clear(GPIO_PORT(LED_PIN), GPIO_PIN(LED_PIN));
#else
gpio_set(GPIO_PORT(LED_PIN), GPIO_PIN(LED_PIN));
#endif // BUSVOODOO
#endif // LED_ON
#endif // LED_PIN
}
@ -98,9 +90,6 @@ inline void led_off(void)
inline void led_toggle(void)
{
#if defined(LED_PIN)
#if defined(BUSVOODOO)
gpio_set_mode(GPIO_PORT(LED_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(LED_PIN)); // set LED pin to push-pull
#endif // BUSVOODOO
gpio_toggle(GPIO_PORT(LED_PIN), GPIO_PIN(LED_PIN));
#endif // LED_PIN
}
@ -187,42 +176,12 @@ void board_setup(void)
#if defined(LED_PIN)
// setup LED
rcc_periph_clock_enable(GPIO_RCC(LED_PIN)); // enable clock for LED
#if defined(BUSVOODOO)
gpio_set_mode(GPIO_PORT(LED_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LED_PIN)); // set LED pin to floating to disable LEDs
#else
gpio_set_mode(GPIO_PORT(LED_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(LED_PIN)); // set LED pin to output push-pull do drive LED
#endif
gpio_set_mode(GPIO_PORT(LED_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(LED_PIN)); // LED it controller by pMOS by default pulled up
led_off(); // switch off LED per default
#endif // LED_PIN
// setup button
#if defined(BUTTON_PIN)
rcc_periph_clock_enable(GPIO_RCC(BUTTON_PIN)); // enable clock for button
gpio_set_mode(GPIO_PORT(BUTTON_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_PIN(BUTTON_PIN)); // set button pin to input
rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
exti_select_source(GPIO_EXTI(BUTTON_PIN), GPIO_PORT(BUTTON_PIN)); // mask external interrupt of this pin only for this port
#if defined(BUTTON_PRESSED) && BUTTON_PRESSED
gpio_clear(GPIO_PORT(BUTTON_PIN), GPIO_PIN(BUTTON_PIN)); // pull down to be able to detect button push (go high)
exti_set_trigger(GPIO_EXTI(BUTTON_PIN), EXTI_TRIGGER_RISING); // trigger when button is pressed
#else
gpio_set(GPIO_PORT(BUTTON_PIN), GPIO_PIN(BUTTON_PIN)); // pull up to be able to detect button push (go low)
exti_set_trigger(GPIO_EXTI(BUTTON_PIN), EXTI_TRIGGER_FALLING); // trigger when button is pressed
#endif
exti_enable_request(GPIO_EXTI(BUTTON_PIN)); // enable external interrupt
nvic_enable_irq(GPIO_NVIC_EXTI_IRQ(BUTTON_PIN)); // enable interrupt
#endif
// reset user input buffer
user_input_available = false;
user_input_i = 0;
user_input_used = 0;
}
#if defined(BUTTON_PIN)
/** interrupt service routine called when button is pressed */
void GPIO_EXTI_ISR(BUTTON_PIN)(void)
{
exti_reset_request(GPIO_EXTI(BUTTON_PIN)); // reset interrupt
button_flag = true; // perform button action
}
#endif

View File

@ -20,7 +20,7 @@
#pragma once
/** enable debugging functionalities */
#define DEBUG true
#define DEBUG false
/** get the length of an array */
#define LENGTH(x) (sizeof(x) / sizeof((x)[0]))
@ -614,78 +614,29 @@
/** @} */
/** @defgroup board_led board LED GPIO
* @note the onboard LED of the USB cable tester is controlled along the display power and USB pull-up
* @{
*/
#if defined(SYSTEM_BOARD) || defined(CORE_BOARD)
#define LED_PIN PA1 /**< GPIO pin (pin 11) */
#define LED_ON 0 /**< LED is on when pin is low */
#elif defined(BLUE_PILL)
#define LED_PIN PC13 /**< GPIO pin */
#define LED_ON 0 /**< LED is on when pin is low */
#elif defined(BLACK_PILL)
#define LED_PIN PB12 /**< GPIO pin */
#define LED_ON 0 /**< LED is on when pin is low */
#elif defined(MAPLE_MINI)
#define LED_PIN PB1 /**< GPIO pin (pin 19) */
#define LED_ON 1 /**< LED is on when pin is high */
#elif defined(STLINKV2) // it's sometimes a STM32F101, but it seems to have all STM32F103 features
/* on ST-Link V2 clone dongle in aluminum case LED is on pin PA9 (remap USART1_TX if used) */
#define LED_PIN PA9 /**< GPIO pin */
#define LED_ON 1 /**< the color and on level depends on the clone */
#elif defined(BLASTER)
#define LED_PIN PA5 /**< GPIO pin */
#define LED_ON 0 /**< red LED on when low (green LED is on when device is powered) */
#elif defined(BUSVOODOO)
#define LED_PIN PA8 /**< GPIO pin */
#define LED_ON 1 /**< blue LED is on when pin is high, red LED is on when pin is low, LED is off when LED is floating */
#endif
// #define LED_PIN PD13 /**< GPIO pin */
// #define LED_ON 0 /**< LED is on when pin is low */
/** @} */
/** @defgroup board_button board user button GPIO
* @{
*/
#if defined(MAPLE_MINI)
/* on maple mini user button is on 32/PB8 */
#define BUTTON_PIN PB8 /**< GPIO pin (pin PB8 on maple mini) */
#define BUTTON_PRESSED 1 /**< pin is high when button is pressed */
#elif defined(CORE_BOARD)
/* on core board user button is on PA8 */
#define BUTTON_PIN PA8 /**< GPIO pin (pin PA8) */
#define BUTTON_PRESSED 0 /**< pin is low when button is pressed */
#endif
/** @} */
/** @defgroup input to force DFU mode on low, even if application is valid
* @{
*/
#if defined(MAPLE_MINI)
/* use button */
#define DFU_FORCE_PIN BUTTON_PIN /**< button pin */
#define DFU_FORCE_VALUE BUTTON_PRESSED /**< button is pulled low unpressed, high pressed to force DFU mode */
#elif defined(CORE_BOARD)
/* use button */
#define DFU_FORCE_PIN BUTTON_PIN /**< button pin */
#define DFU_FORCE_VALUE BUTTON_PRESSED /**< button floating unpressed, connected to ground pressed to force DFU mode */
#elif defined(BLASTER)
#define DFU_FORCE_PIN PA8 /**< GPIO pin (pin PA8, not SWD and UART pin on debug port) */
#define DFU_FORCE_VALUE 0 /**< short to nearby ground connection to force DFU */
#elif defined(BUSVOODOO)
#if BUSVOODOO_HARDWARE_VERSION==0
/* on BusVoodoo v0 DFU input is on PC7 */
#define DFU_FORCE_PIN PC7 /**< GPIO pin (pin PC7) */
#define DFU_FORCE_VALUE 1 /**< pin is pulled low, and goes high when shorted with VUSB */
#else
/* on BusVoodoo vA DFU input is on PC4 */
#define DFU_FORCE_PIN PC4 /**< GPIO pin (pin PC4) */
#define DFU_FORCE_VALUE 1 /**< pin floating, set high when shorted with nearby VCC */
#endif
#else
/* use the JNTRST pin as GPIO (SWJ will still be working, minus NTRST) */
#define DFU_FORCE_PIN PB4 /**< JNTRST pin (needs to be remapped to become PB4) */
#define DFU_FORCE_VALUE 0 /**< must be low to force DFU mode (note: JNTRST is also pulled up after reset) */
#endif
/* since there is no pin left, we re-use SWDIO */
#define DFU_FORCE_PIN PA13 /**< SWDIO pin (needs to be remapped to become PA13) */
#define DFU_FORCE_VALUE 0 /**< must be low to force DFU mode */
/** @} */
/** GPIO pin for display power, onboard LED, and USB D+ pull-up control (using a pMOS) */
#define DISPLAY_POWER_PIN PD13
/** symbol for beginning of the application
* @note this symbol will be provided by the linker script
*/
@ -698,8 +649,7 @@ extern char __application_end;
* @note this symbol will be provided by the linker script
*/
extern char __flash_end;
/** flag set when board user button has been pressed/released */
extern volatile bool button_flag;
/** symbol for the DFU magic word
* @note this symbol will be provided by the linker script
*/

View File

@ -1,611 +0,0 @@
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/** library to communicate with an SD card flash memory using the SPI mode (code)
* @file flash_sdcard.c
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2017
* @note peripherals used: SPI @ref flash_sdcard_spi
* @warning all calls are blocking
* @implements SD Specifications, Part 1, Physical Layer, Simplified Specification, Version 6.00, 10 April 10 2017
* @todo use SPI unidirectional mode, use DMA, force/wait going to idle state when initializing, filter out reserved values, check sector against size
*/
/* standard libraries */
#include <stdint.h> // standard integer types
#include <stdlib.h> // general utilities
/* STM32 (including CM3) libraries */
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
#include <libopencm3/stm32/rcc.h> // real-time control clock library
#include <libopencm3/stm32/gpio.h> // general purpose input output library
#include <libopencm3/stm32/spi.h> // SPI library
#include "global.h" // global utilities
#include "flash_sdcard.h" // SD card header and definitions
/** @defgroup flash_sdcard_spi SPI used to communication with SD card
* @{
*/
#define FLASH_SDCARD_SPI 1 /**< SPI peripheral */
/** @} */
/** if the card has been initialized successfully */
static bool initialized = false;
/** maximum N_AC value (in 8-clock cycles) (time between the response token R1 and data block when reading data (see section 7.5.4)
* @note this is set to N_CR until we can read CSD (see section 7.2.6)
*/
static uint32_t n_ac = 8;
/** is it a Standard Capacity SD card (true), or High Capacity SD cards (false)
* @note this is indicated in the Card Capacity Status bit or OCR (set for high capacity)
* @note this is important for addressing: for standard capacity cards the address is the byte number, for high capacity cards it is the 512-byte block number
*/
static bool sdsc = false;
/** size of card in bytes */
static uint64_t sdcard_size = 0;
/** size of an erase block bytes */
static uint32_t erase_size = 0;
/** table for CRC-7 calculation for the command messages (see section 4.5)
* @note faster than calculating the CRC and doesn't cost a lot of space
* @note generated using pycrc --width=7 --poly=0x09 --reflect-in=false --reflect-out=false --xor-in=0x00 --xor-out=0x00 --generate=table
*/
static const uint8_t crc7_table[] = {
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d, 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42, 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e, 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55, 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28, 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
};
/** wait one SPI round (one SPI word)
*/
static void flash_sdcard_spi_wait(void)
{
spi_send(SPI(FLASH_SDCARD_SPI), 0xffff); // send not command token (i.e. starting with 1)
}
/** read one SPI word
* @return SPI word read
*/
static uint16_t flash_sdcard_spi_read(void)
{
spi_send(SPI(FLASH_SDCARD_SPI), 0xffff); // send not command token (i.e. starting with 1)
(void)SPI_DR(SPI(FLASH_SDCARD_SPI)); // clear RXNE flag (by reading previously received data (not done by spi_read or spi_xref)
while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until Tx buffer is empty before clearing the (previous) RXNE flag
while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_RXNE)); // wait for next data to be available
return SPI_DR(SPI(FLASH_SDCARD_SPI)); // return received adat
}
/** test if card is present
* @return if card has been detected
* @note this use the SD card detection mechanism (CD/CS is high card is inserted due to the internal 50 kOhm resistor)
*/
static bool flash_sdcard_card_detect(void)
{
rcc_periph_clock_enable(RCC_SPI_NSS_PORT(FLASH_SDCARD_SPI)); // enable clock for NSS pin port peripheral for SD card CD signal
gpio_set_mode(SPI_NSS_PORT(FLASH_SDCARD_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set NSS pin as input to read CD signal
gpio_clear(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // pull pin low to avoid false positive when card in not inserted
return (0!=gpio_get(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI))); // read CD signal: is card is present the internal 50 kOhm pull-up resistor will override our 1 MOhm pull-down resistor and set the signal high (see section 6.2)
}
/** transmit command token
* @param[in] index command index
* @param[in] argument command argument
*/
static void flash_sdcard_send_command(uint8_t index, uint32_t argument)
{
uint8_t command[5] = { 0x40+(index&0x3f), argument>>24, argument>>16, argument>>8, argument>>0 }; // commands are 5 bytes long, plus 1 bytes of CRC (see section 7.3.1.1)
uint8_t crc7 = 0x00; // CRC-7 checksum for command message
// send command
for (uint8_t i=0; i<LENGTH(command); i++) {
spi_send(SPI(FLASH_SDCARD_SPI), command[i]); // send data
crc7 = (crc7_table[((crc7<<1)^command[i])])&0x7f; // update checksum
}
spi_send(SPI(FLASH_SDCARD_SPI), (crc7<<1)+0x01); // send CRC value (see section 7.3.1.1)
}
/** transmit command token and receive response token
* @param[in] index command index
* @param[in] argument command argument
* @param[out] response response data to read (if no error occurred)
* @param[in] size size of response to read
* @return response token R1 or 0xff if error occurred or card is not present
*/
static uint8_t flash_sdcard_command_response(uint8_t index, uint32_t argument, uint8_t* response, size_t size)
{
// send command token
gpio_clear(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS low to select slave and start SPI mode (see section 7.2)
flash_sdcard_spi_wait(); // wait for N_CS (min. 0, but it works better with 8 clock cycles) before writing command (see section 7.5.1.1)
flash_sdcard_send_command(index, argument); // send command token
// get response token R1
uint8_t r1 = 0xff; // response token R1 (see section 7.3.2.1)
for (uint8_t i=0; i<8 && r1&0x80; i++) { // wait for N_CR (1 to 8 8 clock cycles) before reading response (see section 7.5.1.1)
r1 = flash_sdcard_spi_read(); // get response (see section 7.3.2.1)
}
if (0x00==(r1&0xfe) && 0!=size && NULL!=response) { // we have to read a response
for (size_t i=0; i<size; i++) {
response[i] = flash_sdcard_spi_read(); // get byte
}
}
// end communication
while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy (= transmission completed)
// wait for N_EC (min. 0) before closing communication (see section 7.5.1.1)
gpio_set(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS high to unselect card
// wait for N_DS (min. 0) before allowing any further communication (see section 7.5.1.1)
return r1;
}
/** read a data block
* @param[out] data data block to read (if no error occurred)
* @param[in] size size of response to read (a multiple of 2)
* @return 0 if succeeded, else control token (0xff for other errors)
*/
static uint8_t flash_sdcard_read_block(uint8_t* data, size_t size)
{
if (size%2 || 0==size || NULL==data) { // can't (and shouldn't) read odd number of bytes
return 0xff;
}
uint8_t token = 0xff; // to save the control block token (see section 7.3.3)
for (uint32_t i=0; i<n_ac && token==0xff; i++) { // wait for N_AC before reading data block (see section 7.5.2.1)
token = flash_sdcard_spi_read(); // get control token (see section 7.3.3)
}
if (0==(token&0xf0)) { // data error token received (see section 7.3.3.3)
if (0==(token&0x0f)) { // unknown error
token = 0xff;
}
} else if (0xfe==token) { // start block token received (see section 7.3.3.2)
// switch to 16-bits SPI data frame so we can use use built-in CRC-16
while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change format
spi_set_dff_16bit(SPI(FLASH_SDCARD_SPI)); // set SPI frame to 16 bits
SPI_CRC_PR(FLASH_SDCARD_SPI) = 0x1021; // set CRC-16-CCITT polynomial for data blocks (x^16+x^12+x^5+1) (see section 7.2.3)
spi_enable_crc(SPI(FLASH_SDCARD_SPI)); // enable and clear CRC
spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
// get block data (ideally use DMA, but switching makes it more complex and this part doesn't take too much time)
for (size_t i=0; i<size/2; i++) {
uint16_t word = flash_sdcard_spi_read(); // get word
data[i*2+0] = (word>>8); // save byte
data[i*2+1] = (word>>0); // save byte
}
flash_sdcard_spi_read(); // read CRC (the CRC after the data block should clear the computed CRC)
if (SPI_CRC_RXR(FLASH_SDCARD_SPI)) { // CRC is wrong
token = 0xff;
} else { // no error occurred
token = 0;
}
// switch back to 8-bit SPI frames
while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change format
spi_disable_crc(SPI(FLASH_SDCARD_SPI)); // disable CRC since we don't use it anymore (and this allows us to clear the CRC next time we use it)
spi_set_dff_8bit(SPI(FLASH_SDCARD_SPI)); // set SPI frame to 8 bits
spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
} else { // start block token not received
token = 0xff;
}
return token;
}
/** write a data block
* @param[in] data data block to write
* @param[in] size size of response to read (a multiple of 2)
* @return data response token (0xff for other errors)
*/
static uint8_t flash_sdcard_write_block(uint8_t* data, size_t size)
{
if (size%2 || 0==size || NULL==data) { // can't (and shouldn't) read odd number of bytes
return 0xff;
}
spi_send(SPI(FLASH_SDCARD_SPI), 0xfe); // send start block token (see section 7.3.3.2)
// switch to 16-bits SPI data frame so we can use use built-in CRC-16
while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change format
spi_set_dff_16bit(SPI(FLASH_SDCARD_SPI)); // set SPI frame to 16 bits
SPI_CRC_PR(FLASH_SDCARD_SPI) = 0x1021; // set CRC-16-CCITT polynomial for data blocks (x^16+x^12+x^5+1) (see section 7.2.3)
spi_enable_crc(SPI(FLASH_SDCARD_SPI)); // enable and clear CRC
spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
// send block data (ideally use DMA, but switching makes it more complex and this part doesn't take too much time)
for (size_t i=0; i<size/2; i++) {
uint16_t word = (data[i*2+0]<<8)+data[i*2+1]; // prepare SPI frame
spi_send(SPI(FLASH_SDCARD_SPI), word); // senf data frame
}
spi_set_next_tx_from_crc(SPI(FLASH_SDCARD_SPI)); // send CRC
// switch back to 8-bit SPI frames
while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change format
spi_set_next_tx_from_buffer(SPI(FLASH_SDCARD_SPI)); // don't send CRC
spi_disable_crc(SPI(FLASH_SDCARD_SPI)); // disable CRC since we don't use it anymore (and this allows us to clear the CRC next time we use it)
spi_set_dff_8bit(SPI(FLASH_SDCARD_SPI)); // set SPI frame to 8 bits
spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
uint8_t token = 0xff;
while (0x01!=(token&0x11)) {
token = flash_sdcard_spi_read(); // get data response token (see section 7.3.3.1)
}
while (0==flash_sdcard_spi_read()); // wait N_EC while the card is busy programming the data
return token;
}
/** get card status
* @param[out] status SD status (512 bits)
* @return response token R2 or 0xffff if error occurred or card is not present
*/
static uint16_t flash_sdcard_status(uint8_t* status)
{
// send CMD55 (APP_CMD) to issue following application command (see table 7-4)
uint8_t r1 = flash_sdcard_command_response(55, 0, NULL, 0); // (see table 7-3)
if ((r1&0xfe)) { // error occurred, not in idle state
return false;
}
// send ACMD13 command
gpio_clear(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS low to select slave and start SPI mode (see section 7.2)
flash_sdcard_spi_wait(); // wait for N_CS (min. 0, but it works better with 8 clock cycles) before writing command (see section 7.5.2.1)
flash_sdcard_send_command(13, 0); // send ACMD13 (SD_STATUS) (see table 7-4)
// get response token R2
uint16_t r2 = 0xffff; // response token R2 (see section 7.3.2.3)
for (uint8_t i=0; i<8 && r2&0x8000; i++) { // wait for N_CR (1 to 8 8 clock cycles) before reading response (see section 7.5.1.1)
r2 = (flash_sdcard_spi_read()<<8); // get first byte of response (see section 7.3.2.1)
}
if (0==(r2&0x8000)) { // got the first byte
r2 += flash_sdcard_spi_read(); // read second byte (see 7.3.2.3)
}
// get data block
if (0==r2) { // no error
if (flash_sdcard_read_block(status, 64)) { // read 512 bits data block containing SD status
r2 |= (1<<11); // set communication error
}
}
// end communication
while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy (= transmission completed)
// wait for N_EC (min. 0) before closing communication (see section 7.5.1.1)
gpio_set(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS high to unselect card
// wait for N_DS (min. 0) before allowing any further communication (see section 7.5.1.1)
return r2;
}
/** transmit command token, receive response token and data block
* @param[in] index command index
* @param[in] argument command argument
* @param[out] data data block to read (if no error occurred)
* @param[in] size size of data to read (a multiple of 2)
* @return response token R1 or 0xff if error occurred or card is not present
*/
static uint8_t flash_sdcard_data_read(uint8_t index, uint32_t argument, uint8_t* data, size_t size)
{
if (size%2 || 0==size || NULL==data) { // can't (and shouldn't) read odd number of bytes
return 0xff;
}
// send command token
gpio_clear(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS low to select slave and start SPI mode (see section 7.2)
flash_sdcard_spi_wait(); // wait for N_CS (min. 0, but it works better with 8 clock cycles) before writing command (see section 7.5.2.1)
flash_sdcard_send_command(index, argument); // send command token
// get response token R1
uint8_t r1 = 0xff; // response token R1 (see section 7.3.2.1)
for (uint8_t i=0; i<8 && r1&0x80; i++) { // wait for N_CR (1 to 8 8 clock cycles) before reading response (see section 7.5.1.1)
r1 = flash_sdcard_spi_read(); // get response (see section 7.3.2.1)
}
// get data block
if (0x00==r1) { // we can read a data block
if (flash_sdcard_read_block(data, size)) { // read data block
r1 |= (1<<3); // set communication error
}
}
// end communication
while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy (= transmission completed)
// wait for N_EC (min. 0) before closing communication (see section 7.5.1.1)
gpio_set(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS high to unselect card
// wait for N_DS (min. 0) before allowing any further communication (see section 7.5.1.1)
return r1;
}
/** transmit command token, receive response token and write data block
* @param[in] index command index
* @param[in] argument command argument
* @param[out] data data block to write
* @param[in] size size of data to write (a multiple of 2)
* @return data response token, or 0xff if error occurred or card is not present
* @note at the end of a write operation the SD status should be check to ensure no error occurred during programming
*/
static uint8_t flash_sdcard_data_write(uint8_t index, uint32_t argument, uint8_t* data, size_t size)
{
if (size%2 || 0==size || NULL==data) { // can't (and shouldn't) write odd number of bytes
return 0xff;
}
// send command token
gpio_clear(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS low to select slave and start SPI mode (see section 7.2)
flash_sdcard_spi_wait(); // wait for N_CS (min. 0, but it works better with 8 clock cycles) before writing command (see section 7.5.2.1)
flash_sdcard_send_command(index, argument); // send command token
// get response token R1
uint8_t r1 = 0xff; // response token R1 (see section 7.3.2.1)
for (uint8_t i=0; i<8 && r1&0x80; i++) { // wait for N_CR (1 to 8 8 clock cycles) before reading response (see section 7.5.1.1)
r1 = flash_sdcard_spi_read(); // get response (see section 7.3.2.1)
}
// write data block
uint8_t drt = 0xff; // data response token (see section 7.3.3.1)
if (0x00==r1) { // we have to write the data block
drt = flash_sdcard_write_block(data, size); // write data block
}
// end communication
while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy (= transmission completed)
// wait for N_EC (min. 0) before closing communication (see section 7.5.1.1)
gpio_set(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS high to unselect card
// wait for N_DS (min. 0) before allowing any further communication (see section 7.5.1.1)
return drt;
}
bool flash_sdcard_setup(void)
{
// reset values
initialized = false;
n_ac = 8;
sdcard_size = 0;
erase_size = 0;
// check if card is present
if (!flash_sdcard_card_detect()) {
return false;
}
// configure SPI peripheral
rcc_periph_clock_enable(RCC_SPI_SCK_PORT(FLASH_SDCARD_SPI)); // enable clock for GPIO peripheral for clock signal
gpio_set_mode(SPI_SCK_PORT(FLASH_SDCARD_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_SCK_PIN(FLASH_SDCARD_SPI)); // set SCK as output (clock speed will be negotiated later)
rcc_periph_clock_enable(RCC_SPI_MOSI_PORT(FLASH_SDCARD_SPI)); // enable clock for GPIO peripheral for MOSI signal
gpio_set_mode(SPI_MOSI_PORT(FLASH_SDCARD_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_MOSI_PIN(FLASH_SDCARD_SPI)); // set MOSI as output
rcc_periph_clock_enable(RCC_SPI_MISO_PORT(FLASH_SDCARD_SPI)); // enable clock for GPIO peripheral for MISO signal
gpio_set_mode(SPI_MISO_PORT(FLASH_SDCARD_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SPI_MISO_PIN(FLASH_SDCARD_SPI)); // set MISO as input
gpio_set(SPI_MISO_PORT(FLASH_SDCARD_SPI), SPI_MISO_PIN(FLASH_SDCARD_SPI)); // pull pin high to detect when the card is not answering (or not present) since responses always start with MSb 0
rcc_periph_clock_enable(RCC_SPI_NSS_PORT(FLASH_SDCARD_SPI)); // enable clock for GPIO peripheral for NSS (CS) signal
gpio_set_mode(SPI_NSS_PORT(FLASH_SDCARD_SPI), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set NSS (CS) as output
rcc_periph_clock_enable(RCC_AFIO); // enable clock for SPI alternate function
rcc_periph_clock_enable(RCC_SPI(FLASH_SDCARD_SPI)); // enable clock for SPI peripheral
spi_reset(SPI(FLASH_SDCARD_SPI)); // clear SPI values to default
spi_init_master(SPI(FLASH_SDCARD_SPI), SPI_CR1_BAUDRATE_FPCLK_DIV_256, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); // initialise SPI as master, divide clock by 256 (72E6/256=281 kHz) since maximum SD card clock frequency (fOD, see section 7.8/6.6.6) during initial card-identification mode is 400 kHz (maximum SPI PCLK clock is 72 Mhz, depending on which SPI is used), set clock polarity to idle low (not that important), set clock phase to do bit change on falling edge (from SD card spec, polarity depends on clock phase), use 8 bits frames (as per spec), use MSb first
spi_set_full_duplex_mode(SPI(FLASH_SDCARD_SPI)); // ensure we are in full duplex mode
spi_enable_software_slave_management(SPI(FLASH_SDCARD_SPI)); // control NSS (CS) manually
spi_set_nss_high(SPI(FLASH_SDCARD_SPI)); // set NSS high (internally) so we can output
spi_disable_ss_output(SPI(FLASH_SDCARD_SPI)); // disable NSS output since we control CS manually
gpio_set(SPI_NSS_PORT(FLASH_SDCARD_SPI), SPI_NSS_PIN(FLASH_SDCARD_SPI)); // set CS high to unselect card
// sadly we can't use the interrupts as events to sleep (WFE) since sleep disables also communication (e.g. going to sleep until Rx buffer is not empty prevents transmission)
spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI
// start card-identification (see section 7.2.1/4.2)
uint8_t r1 = 0;
// send CMD0 (GO_IDLE_START) to start the card identification (see section 7.2.1)
r1 = flash_sdcard_command_response(0, 0, NULL, 0); // (see table 7-3)
if (0x01!=r1) { // error occurred, not in idle state
return false;
}
// send CMD8 (SEND_IF_COND) to inform about voltage (1: 2.7-3.6V, aa: recommended check pattern) (see section 7.2.1)
uint8_t r7[4] = {0}; // to store response toke R7 (see section 7.3.2.6)
r1 = flash_sdcard_command_response(8, 0x000001aa, r7, sizeof(r7)); // (see table 7-3)
if (0x01==r1) { // command supported, in idle state
if (!(r7[2]&0x1)) { // 2.7-3.6V not supported (see table 5-1)
return false;
} else if (0xaa!=r7[3]) { // recommended pattern not returned (see section 4.3.13)
return false;
}
} else if (0x05!=r1) { // illegal command (cards < physical spec v2.0 don't support CMD8) (see section 7.2.1)
return false;
}
// send CMD58 (READ_OCR) to read Operation Conditions Register (see section 7.2.1)
uint8_t r3[4] = {0}; // to store response token R3 (see section 7.3.2.4)
r1 = flash_sdcard_command_response(58, 0, r3, sizeof(r3)); // (see table 7-3)
if (0x01!=r1) { // error occurred, not in idle state
return false;
} else if (!(r3[1]&0x30)) { // 3.3V not supported (see table 5-1)
return false;
}
do {
// send CMD55 (APP_CMD) to issue following application command (see table 7-4)
r1 = flash_sdcard_command_response(55, 0, NULL, 0); // (see table 7-3)
if (0x01!=r1) { // error occurred, not in idle state
return false;
}
// send ACMD41 (SD_SEND_OP_COND) with Host Capacity Support (0b: SDSC Only Host, 1b: SDHC or SDXC Supported) (see section 7.2.1)
r1 = flash_sdcard_command_response(41, 0x40000000, NULL, 0); // (see table 7-4)
if (r1&0xfe) { // error occurred
return false;
}
} while (0x00!=r1); // wait until card is ready (see section 7.2.1)
// send CMD58 (READ_OCR) to read Card Capacity Status (CCS) (see section 7.2.1)
r1 = flash_sdcard_command_response(58, 0, r3, sizeof(r3)); // (see table 7-3)
if (r1) { // error occurred
return false;
}
// card power up status bit (bit 31) is set when power up is complete (see table 5-1)
if (0x00==(r3[0]&0x80)) {
return false;
}
sdsc = (0==(r3[0]&0x40)); // CCS is bit 30 in OCR (see table 5-1)
// now the card identification is complete and we should be in data-transfer mode (see figure 7-1)
// we can switch clock frequency to fPP (max. 25 MHz) (see section 4.3/6.6.6)
while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change clock speed
spi_set_baudrate_prescaler(SPI(FLASH_SDCARD_SPI), SPI_CR1_BR_FPCLK_DIV_4); // set clock speed to 18 MHz (72/4=18, < 25 MHz)
spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
// send CMD9 (SEND_CSD) to get Card Specific Data (CSD) and calculate N_AC (see section 7.2.6)
uint8_t csd[16] = {0}; // CSD response (see chapter 7.2.6)
r1 = flash_sdcard_data_read(9, 0, csd, sizeof(csd)); // (see table 7-3)
if (r1) { // error occurred
return false;
}
// check if CSD structure version matches capacity (see section 5.3.1)
if ((sdsc && (csd[0]>>6)) || (!sdsc && 0==(csd[0]>>6))) {
return false;
}
// calculate N_AC value (we use our set minimum frequency 16 MHz to calculate time)
if (sdsc) { // calculate N_AC using TAAC and NSAC
static const float TAAC_UNITS[] = {1E-9, 10E-9, 100E-9, 1E-6, 10E-6, 100E-6, 1E-3, 10E-3}; // (see table 5-5)
static const float TAAC_VALUES[] = {10.0, 1.0, 1.2, 1.3, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 7.0, 8.0}; // (see table 5-5)
double taac = TAAC_VALUES[(csd[1]>>2)&0xf]*TAAC_UNITS[csd[1]&0x7]; // time in ns
n_ac=100*((taac*16E6)+(csd[2]*100))/8; // (see section 7.5.4)
} else { // value is fixed to 100 ms
n_ac=100E-3*16E6/8;
}
// calculate card size
if (sdsc) { // see section 5.3.2
uint16_t c_size = (((uint16_t)csd[6]&0x03)<<10)+((uint16_t)csd[7]<<2)+(csd[8]>>6);
uint8_t c_size_mutl = ((csd[9]&0x03)<<1)+((csd[10]&0x80)>>7);
uint8_t read_bl_len = (csd[5]&0x0f);
sdcard_size = ((c_size+1)*(1UL<<(c_size_mutl+2)))*(1UL<<read_bl_len);
} else { // see section 5.3.3
uint32_t c_size = ((uint32_t)(csd[7]&0x3f)<<16)+((uint16_t)csd[8]<<8)+csd[9];
sdcard_size = (c_size+1)*(512<<10);
}
// calculate erase size
if (sdsc) { // see section 5.3.2
erase_size = (((csd[10]&0x3f)<<1)+((csd[11]&0x80)>>7)+1)<<(((csd[12]&0x03)<<2)+(csd[13]>>6));
} else {
uint8_t status[64] = {0}; // SD status (see section 4.10.2)
uint16_t r2 = flash_sdcard_status(status); // get status (see table 7-4)
if (r2) { // error occurred
return false;
}
erase_size = (8192UL<<(status[10]>>4)); // calculate erase size (see table 4-44, section 4.10.2.4)
}
// ensure block length is 512 bytes for SDSC (should be per default) to we match SDHC/SDXC block size
if (sdsc) {
r1 = flash_sdcard_command_response(16, 512, NULL, 0); // set block size using CMD16 (SET_BLOCKLEN) (see table 7-3)
if (r1) { // error occurred
return false;
}
}
// try to switch to high speed mode (see section 7.2.14/4.3.10)
if (csd[4]&0x40) { // ensure CMD6 is supported by checking if command class 10 is set
uint32_t n_ac_back = n_ac; // backup N_AC
n_ac = 100E-3*16E6/8; // temporarily set timeout to 100 ms (see section 4.3.10.1)
// query access mode (group function 1) to check if high speed is supported (fPP=50MHz at 3.3V, we can be faster)
uint8_t fnc[64] = {0}; // function status response (see table 4-12)
r1 = flash_sdcard_data_read(6, 0x00fffff1, fnc, sizeof(fnc)); // check high speed function using CMD6 (SWITCH_FUNC) to check (mode 0) access mode (function group 1) (see table 7-3/4-30)
if (r1) { // error occurred
return false;
}
if (0x1==(fnc[16]&0x0f)) { // we can to access mode function 1 (see table 4-12)
r1 = flash_sdcard_data_read(6, 0x80fffff1, fnc, sizeof(fnc)); // switch to high speed function using CMD6 (SWITCH_FUNC) to switch (mode 1) access mode (function group 1) (see table 7-3/4-30)
if (r1) { // error occurred
return false;
}
if (0x1!=(fnc[16]&0x0f)) { // could not switch to high speed
return false;
}
// we can switch clock frequency to fPP (max. 50 MHz) (see section 6.6.7)
while (!(SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_TXE)); // wait until the end of any transmission
while (SPI_SR(SPI(FLASH_SDCARD_SPI))&SPI_SR_BSY); // wait until not busy before disabling
spi_disable(SPI(FLASH_SDCARD_SPI)); // disable SPI to change clock speed
spi_set_baudrate_prescaler(SPI(FLASH_SDCARD_SPI), SPI_CR1_BR_FPCLK_DIV_2); // set clock speed to 36 MHz (72/2=36 < 50 MHz)
spi_enable(SPI(FLASH_SDCARD_SPI)); // enable SPI back
n_ac_back /= 2; // since we go twice faster the N_AC timeout has to be halved
}
n_ac = n_ac_back; // restore N_AC
}