diff --git a/Makefile b/Makefile index 0627ffc..36c739c 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ MAIN = avrrfm.c SRC = bitmaps.c colorspace.c dejavu.c display.c font.c i2c.c mcp9808.c \ - sdcard.c spi.c tft.c unifont.c usart.c rfm.c + spi.c tft.c unifont.c usart.c rfm.c sdc.c CC = avr-gcc OBJCOPY = avr-objcopy @@ -43,14 +43,13 @@ TARGET = $(strip $(basename $(MAIN))) SRC += $(TARGET).c -SRC += librfm.a +SRC += librfm.a libsdc.a OBJ = $(SRC:.c=.o) OBJ = $(SRC:.S=.o) $(TARGET).elf: bitmaps.h colorspace.h dejavu.h display.h font.h i2c.h \ - mcp9808.h pins.h sdcard.h spi.h tft.h types.h unifont.h \ - usart.h utils.h Makefile + mcp9808.h pins.h spi.h tft.h types.h unifont.h usart.h utils.h Makefile all: $(TARGET).hex diff --git a/README.md b/README.md index 84d36e9..8516b1e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# AVRRFM +# avrrfm ## About @@ -11,8 +11,9 @@ are put to power down/sleep mode in between transmissions. The idle current is ~57 uA, which is still quite a lot (< 10 uA should be possible), but already better than 8 mA 🙂 -There is basic SD card support to test sending larger amounts of data, but -it might be useful for something else like a data logger. +There is basic [SD card support](https://github.com/gitdode/libsdc/tree/main) +to test sending larger amounts of data, but it might be useful for something +else like a data logger. ![IMG_20250322_012126](https://github.com/user-attachments/assets/e641ddd8-ca52-4149-8d73-3dcee39b7768) diff --git a/avrrfm.c b/avrrfm.c index 7045de2..2080971 100644 --- a/avrrfm.c +++ b/avrrfm.c @@ -28,8 +28,8 @@ #include "spi.h" #include "utils.h" #include "librfm.h" +#include "libsdc.h" #include "mcp9808.h" -#include "sdcard.h" #include "tft.h" #include "display.h" #include "dejavu.h" diff --git a/librfm.a b/librfm.a index 0a14ec8..b241fb2 100644 --- a/librfm.a +++ b/librfm.a Binary files differ diff --git a/librfm.h b/librfm.h index 332d475..949cc86 100644 --- a/librfm.h +++ b/librfm.h @@ -97,19 +97,19 @@ /** * Turns the radio on by pulling its reset pin LOW. - * PORT_RFM &= ~(1 << PIN_RRST); + * PORTB &= ~(1 << PB0); */ void _rfmOn(void); /** * Selects the radio to talk to via SPI. - * PORT_RFM &= ~(1 << PIN_RCS); + * PORTB &= ~(1 << PB1); */ void _rfmSel(void); /** * Deselects the radio to talk to via SPI. - * PORT_RFM |= (1 << PIN_RCS); + * PORTB |= (1 << PB1); */ void _rfmDes(void); diff --git a/libsdc.a b/libsdc.a new file mode 100644 index 0000000..f25eea0 --- /dev/null +++ b/libsdc.a Binary files differ diff --git a/libsdc.h b/libsdc.h new file mode 100644 index 0000000..b277fa2 --- /dev/null +++ b/libsdc.h @@ -0,0 +1,131 @@ +/* + * File: libsdc.h + * Author: torsten.roemer@luniks.net + * + * Created on 25.03.2025, 20:29 + */ + +#ifndef SDCARD_H +#define SDCARD_H + +#include +#include +#include + +#define CMD0 0 +#define CMD0_ARG 0x00000000 +#define CMD0_CRC 0x94 + +#define CMD8 8 +#define CMD8_ARG 0x0000001aa +#define CMD8_CRC 0x86 + +#define CMD12 12 +#define CMD12_ARG 0x00000000 +#define CMD12_CRC 0x60 + +#define CMD17 17 +#define CMD17_CRC 0x00 + +#define CMD18 18 +#define CMD18_CRC 0x00 + +#define CMD24 24 +#define CMD24_CRC 0x00 + +#define CMD55 55 +#define CMD55_ARG 0x00000000 +#define CMD55_CRC 0x64 + +#define CMD58 58 +#define CMD58_ARG 0x00000000 +#define CMD58_CRC 0xfc + +#define ACMD41 41 +#define ACMD41_ARG 0x40000000 +#define ACMD41_CRC 0x76 + +// TODO depends on SPI SCK frequency +#define SD_MAX_READ 50000 // SPI clock ticks in 100 ms +#define SD_MAX_WRITE 125000 // SPI clock ticks in 250 ms + +#define SD_BLOCK_SIZE 512 + +#define SD_CMD_ILLEGAL 2 + +#define SD_SUCCESS 0x00 +#define SD_START_BLOCK 0xfe + +/** + * Pointer to a function that takes an array of bytes + * and returns a boolean. + */ +typedef bool (*SDConsumer)(uint8_t*); + +/** + * F_CPU dependent delay of 10 milliseconds. + * _delay_ms(10); + * + * @param ms + */ +void _sdcDelay10(void); + +/** + * Selects the radio to talk to via SPI. + * PORTB &= ~(1 << PB1); + */ +void _sdcSel(void); + +/** + * Deselects the radio to talk to via SPI. + * PORTB |= (1 << PB1); + */ +void _sdcDes(void); + +/** + * SPI transmits/receives given data/returns it. + * + * @param data + * @return data + */ +uint8_t _sdcTx(uint8_t data); + +/** + * Initializes the SD Card and returns true on success, false otherwise. + * + * @return true on success, false otherwise + */ +bool initSDCard(void); + +/** + * Reads a single block of 512 bytes at the given address into + * the given buffer and returns true on success, false otherwise. + * + * @param address address in 512 byte units + * @param block 512 byte buffer + * @return success + */ +bool readSingleBlock(uint32_t address, uint8_t *block); + +/** + * Reads multiple blocks of 512 bytes starting at the given address + * and, for each block, passes the buffer to the given function. + * By returning false, the function can request to stop reading blocks. + * + * @param address + * @param consume + * @return success + */ +bool readMultiBlock(uint32_t address, SDConsumer consume); + +/** + * Writes a single block of 512 bytes starting at the given address + * from the given buffer and returns true on success, false otherwise. + * + * @param address address in 512 byte units + * @param block 512 byte buffer + * @return success + */ +bool writeSingleBlock(uint32_t address, uint8_t *block); + +#endif /* SDCARD_H */ diff --git a/nbproject/Makefile-Custom.mk b/nbproject/Makefile-Custom.mk index bc953e0..54aaa32 100644 --- a/nbproject/Makefile-Custom.mk +++ b/nbproject/Makefile-Custom.mk @@ -43,12 +43,12 @@ ${OBJECTDIR}/_ext/48b9ad18/font.o \ ${OBJECTDIR}/_ext/48b9ad18/i2c.o \ ${OBJECTDIR}/_ext/48b9ad18/mcp9808.o \ - ${OBJECTDIR}/_ext/48b9ad18/sdcard.o \ + ${OBJECTDIR}/_ext/48b9ad18/rfm.o \ + ${OBJECTDIR}/_ext/48b9ad18/sdc.o \ ${OBJECTDIR}/_ext/48b9ad18/spi.o \ ${OBJECTDIR}/_ext/48b9ad18/tft.o \ ${OBJECTDIR}/_ext/48b9ad18/unifont.o \ - ${OBJECTDIR}/_ext/48b9ad18/usart.o \ - ${OBJECTDIR}/rfm.o + ${OBJECTDIR}/_ext/48b9ad18/usart.o # C Compiler Flags @@ -107,9 +107,13 @@ ${MKDIR} -p ${OBJECTDIR}/_ext/48b9ad18 $(COMPILE.c) -g -DBAUD=38400 -DDRIVER=1 -DF_CPU=16000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -o ${OBJECTDIR}/_ext/48b9ad18/mcp9808.o /home/dode/dev/avrrfm/mcp9808.c -${OBJECTDIR}/_ext/48b9ad18/sdcard.o: /home/dode/dev/avrrfm/sdcard.c +${OBJECTDIR}/_ext/48b9ad18/rfm.o: /home/dode/dev/avrrfm/rfm.c ${MKDIR} -p ${OBJECTDIR}/_ext/48b9ad18 - $(COMPILE.c) -g -DBAUD=38400 -DDRIVER=1 -DF_CPU=16000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -o ${OBJECTDIR}/_ext/48b9ad18/sdcard.o /home/dode/dev/avrrfm/sdcard.c + $(COMPILE.c) -g -DBAUD=38400 -DDRIVER=1 -DF_CPU=16000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -o ${OBJECTDIR}/_ext/48b9ad18/rfm.o /home/dode/dev/avrrfm/rfm.c + +${OBJECTDIR}/_ext/48b9ad18/sdc.o: /home/dode/dev/avrrfm/sdc.c + ${MKDIR} -p ${OBJECTDIR}/_ext/48b9ad18 + $(COMPILE.c) -g -DBAUD=38400 -DDRIVER=1 -DF_CPU=16000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -o ${OBJECTDIR}/_ext/48b9ad18/sdc.o /home/dode/dev/avrrfm/sdc.c ${OBJECTDIR}/_ext/48b9ad18/spi.o: /home/dode/dev/avrrfm/spi.c ${MKDIR} -p ${OBJECTDIR}/_ext/48b9ad18 @@ -127,10 +131,6 @@ ${MKDIR} -p ${OBJECTDIR}/_ext/48b9ad18 $(COMPILE.c) -g -DBAUD=38400 -DDRIVER=1 -DF_CPU=16000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -o ${OBJECTDIR}/_ext/48b9ad18/usart.o /home/dode/dev/avrrfm/usart.c -${OBJECTDIR}/rfm.o: rfm.c - ${MKDIR} -p ${OBJECTDIR} - $(COMPILE.c) -g -DBAUD=38400 -DDRIVER=1 -DF_CPU=16000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -o ${OBJECTDIR}/rfm.o rfm.c - # Subprojects .build-subprojects: diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 3dcff70..4b51237 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -12,7 +12,7 @@ mcp9808.c mcp9808.h rfm.c - sdcard.c + sdc.c spi.c tft.c unifont.c @@ -70,7 +70,9 @@ - + + + @@ -80,8 +82,6 @@ - - diff --git a/sdc.c b/sdc.c new file mode 100644 index 0000000..9bdcd9d --- /dev/null +++ b/sdc.c @@ -0,0 +1,28 @@ +/* + * File: sdc.c + * Author: torsten.roemer@luniks.net + * + * Created on 25.03.2025, 21:13 + */ + +#include + +#include "libsdc.h" +#include "pins.h" +#include "spi.h" + +void _sdcDelay10() { + _delay_ms(10); +} + +void _sdcSel() { + PORT_SDC &= ~(1 << PIN_SDCS); +} + +void _sdcDes() { + PORT_SDC |= (1 << PIN_SDCS); +} + +uint8_t _sdcTx(uint8_t data) { + return transmit(data); +} \ No newline at end of file diff --git a/sdcard.c b/sdcard.c deleted file mode 100644 index aecdf5f..0000000 --- a/sdcard.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * File: sdcard.c - * Author: torsten.roemer@luniks.net - * - * Thanks to http://rjhcoding.com/avrc-sd-interface-1.php ff. - * - * Created on 24. Februar 2024, 00:13 - */ - -#include "sdcard.h" - -/** - * Transmits the given command, argument and CRC value. - * - * @param command - * @param argument - * @param crc - */ -static void command(uint8_t command, uint32_t argument, uint8_t crc) { - // 6-bit command, start bit is always 0, transmitter bit is 1 (host command) - transmit(command | 0x40); - - transmit(argument >> 24); - transmit(argument >> 16); - transmit(argument >> 8); - transmit(argument); - - // 7-bit crc, end bit is always 1 - transmit(crc | 0x01); -} - -/** - * Reads an R1 response and returns it. - * - * @return R1 - */ -static uint8_t readR1(void) { - uint8_t i = 0; - uint8_t response; - - // poll up to 8 times for response - while ((response = transmit(0xff)) == 0xff) { - i++; - if (i > 8) { - break; - } - } - - return response; -} - -/** - * Reads an R3/R7 response into the given array of 5 bytes. - * - * @param R3/R7 - */ -static void readR3_7(uint8_t *response) { - // read R1 - response[0] = readR1(); - - // stop reading if R1 indicates an error - if (response[0] > 0x01) { - return; - } - - response[1] = transmit(0xff); - response[2] = transmit(0xff); - response[3] = transmit(0xff); - response[4] = transmit(0xff); -} - -/** - * Selects the SD card to talk to via SPI. - */ -static void sdCardSel(void) { - PORT_SDC &= ~(1 << PIN_SDCS); -} - -/** - * Deselects the SD card to talk to via SPI. - */ -static void sdCardDes(void) { - PORT_SDC |= (1 << PIN_SDCS); -} - -/** - * SPI selects the SD card with extra clocks before and after. - */ -static void select(void) { - transmit(0xff); - sdCardSel(); - transmit(0xff); -} - -/** - * SPI deselects the SD card with extra clocks before and after. - */ -static void deselect(void) { - transmit(0xff); - sdCardDes(); - transmit(0xff); -} - -/** - * Supplies ramp up time. - */ -static void powerOn(void) { - _delay_ms(100); - deselect(); - - // supply at least 74 clocks - for (uint8_t i = 0; i < 10; i++) { - transmit(0xff); - } -} - -/** - * Sends CMD0 to set idle SPI mode and returns the R1 response. - * - * @return R1 - */ -static uint8_t sendIdle(void) { - select(); - - command(CMD0, CMD0_ARG, CMD0_CRC); - uint8_t response = readR1(); - - deselect(); - - return response; -} - -/** - * Sends CMD8 to check version and voltage and reads the R7 response - * into the given array of 5 bytes. - * - * @param R7 - */ -static void sendIfCond(uint8_t *response) { - select(); - - command(CMD8, CMD8_ARG, CMD8_CRC); - readR3_7(response); - - deselect(); -} - -/** - * Sends CMD55 to tell that an app command is next and returns the R1 response. - * - * @return R1 - */ -static uint8_t sendApp(void) { - select(); - - command(CMD55, CMD55_ARG, CMD55_CRC); - uint8_t response = readR1(); - - deselect(); - - return response; -} - -/** - * Sends CMD58 to read the OCR register and reads the R3 response - * into the given array of 5 bytes. - * - * @param R3 - */ -static void sendOCR(uint8_t *response) { - select(); - - command(CMD58, CMD58_ARG, CMD58_CRC); - readR3_7(response); - - deselect(); -} - -/** - * Sends ACMD41 to start initialization and returns the R1 response. - * - * @return R1 - */ -static uint8_t sendOpCond(void) { - select(); - - command(ACMD41, ACMD41_ARG, ACMD41_CRC); - uint8_t response = readR1(); - - deselect(); - - return response; -} - -bool initSDCard(void) { - uint8_t response[5]; - - // power on - powerOn(); - - // CMD0 - go to idle state - response[0] = sendIdle(); - if (response[0] != 0x01) { - // retry solves failure possibly caused by another component - // on the same SPI bus - response[0] = sendIdle(); - } - if (response[0] != 0x01) { - printString("SD card error 0\r\n"); - return false; - } - - // CMD8 - send interface condition - sendIfCond(response); - if (response[0] & (1 << SD_CMD_ILLEGAL)) { - printString("SD card is V1.x or not SD card\r\n"); - return false; - } else if (response[0] > 0x01) { - printString("SD card error 8\r\n"); - return false; - } else if (response[4] != 0xaa) { - printString("SD card echo pattern mismatch\r\n"); - return false; - } - - // initialize to ready state - uint8_t attempts = 0; - do { - if (attempts > 100) { - printString("SD card did not become ready\r\n"); - return false; - } - - // CMD55 - send app command - response[0] = sendApp(); - if (response[0] < 0x02) { - // ACMD41 - start initialization - response[0] = sendOpCond(); - } - - _delay_ms(10); - attempts++; - } while (response[0] != SD_SUCCESS); - - // CMD58 - send operation conditions register - sendOCR(response); - if (response[0] > 0x01) { - printString("SD card error 58\r\n"); - return false; - } else if (!(response[1] & 0x80)) { - printString("SD card not ready\r\n"); - return false; - } - - printString("SD card ready\r\n"); - - return true; -} - -bool readSingleBlock(uint32_t address, uint8_t *block) { - select(); - - command(CMD17, address, CMD17_CRC); - uint8_t response = readR1(); - uint8_t token = 0xff; - bool success = false; - - if (response == SD_SUCCESS) { - // read command was successful, wait for start block token - for (uint16_t attempt = 0; attempt < SD_MAX_READ && token == 0xff; attempt++) { - token = transmit(0xff); - } - - if (token == SD_START_BLOCK) { - // start block token received, 512 data bytes follow - for (uint16_t i = 0; i < SD_BLOCK_SIZE; i++) { - block[i] = transmit(0xff); - } - - // 16-bit CRC (ignore for now) - transmit(0xff); - transmit(0xff); - - success = true; - } - } - - deselect(); - - return success; -} - -bool readMultiBlock(uint32_t address, Consumer consume) { - select(); - - command(CMD18, address, CMD18_CRC); - uint8_t response = readR1(); - bool success = false; - bool cont = false; - uint8_t block[SD_BLOCK_SIZE]; - - if (response == SD_SUCCESS) { - // read command was successful - do { - // wait for start block token - uint8_t token = 0xff; - for (uint16_t attempt = 0; attempt < SD_MAX_READ && token == 0xff; attempt++) { - token = transmit(0xff); - } - - if (token == SD_START_BLOCK) { - // start block token received, 512 data bytes follow - for (uint16_t i = 0; i < SD_BLOCK_SIZE; i++) { - block[i] = transmit(0xff); - } - - // 16-bit CRC (ignore for now) - transmit(0xff); - transmit(0xff); - - cont = consume(block); - } else { - break; - } - } while (cont); - - deselect(); - select(); - - command(CMD12, CMD12_ARG, CMD12_CRC); - // stuff byte on CMD12? - transmit(0xff); - response = readR1(); - - if (response == SD_SUCCESS) { - // wait for not busy - uint8_t busy = 0x00; - for (uint16_t attempt = 0; attempt < SD_MAX_READ && busy == 0x00; attempt++) { - busy = transmit(0xff); - } - success = busy != 0x00; - } - } - - deselect(); - - return success; -} - -bool writeSingleBlock(uint32_t address, uint8_t *block) { - select(); - - command(CMD24, address, CMD24_CRC); - uint8_t response = readR1(); - uint8_t token = 0xff; - bool success = false; - - if (response == SD_SUCCESS) { - // write command was successful, send start block token - transmit(SD_START_BLOCK); - - // write 512 data bytes - for (uint16_t i = 0; i < SD_BLOCK_SIZE; i++) { - transmit(block[i]); - } - - // wait for data response - for (uint16_t attempt = 0; attempt < SD_MAX_WRITE && token == 0xff; attempt++) { - token = transmit(0xff); - } - - if ((token & 0x0f) == 0x05) { - // data was accepted, wait while busy programming data - for (uint16_t attempt = 0; attempt < SD_MAX_WRITE && token == 0x00; attempt++) { - token = transmit(0xff); - } - - success = true; - } - } - - deselect(); - - return success; -} diff --git a/sdcard.h b/sdcard.h deleted file mode 100644 index 24fe0ee..0000000 --- a/sdcard.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * File: sdcard.h - * Author: torsten.roemer@luniks.net - * - * Created on 24. Februar 2024, 00:13 - */ - -#ifndef SDCARD_H -#define SDCARD_H - -#include -#include -#include "pins.h" -#include "spi.h" -#include "usart.h" -#include "types.h" - -#define CMD0 0 -#define CMD0_ARG 0x00000000 -#define CMD0_CRC 0x94 - -#define CMD8 8 -#define CMD8_ARG 0x0000001aa -#define CMD8_CRC 0x86 - -#define CMD12 12 -#define CMD12_ARG 0x00000000 -#define CMD12_CRC 0x60 - -#define CMD17 17 -#define CMD17_CRC 0x00 - -#define CMD18 18 -#define CMD18_CRC 0x00 - -#define CMD24 24 -#define CMD24_CRC 0x00 - -#define CMD55 55 -#define CMD55_ARG 0x00000000 -#define CMD55_CRC 0x64 - -#define CMD58 58 -#define CMD58_ARG 0x00000000 -#define CMD58_CRC 0xfc - -#define ACMD41 41 -#define ACMD41_ARG 0x40000000 -#define ACMD41_CRC 0x76 - -// TODO depends on SPI SCK frequency -#define SD_MAX_READ 50000 // SPI clock ticks in 100 ms -#define SD_MAX_WRITE 125000 // SPI clock ticks in 250 ms - -#define SD_BLOCK_SIZE 512 - -#define SD_CMD_ILLEGAL 2 - -#define SD_SUCCESS 0x00 -#define SD_START_BLOCK 0xfe - -/** - * Initializes the SD Card and returns true on success, false otherwise. - * - * @return true on success, false otherwise - */ -bool initSDCard(void); - -/** - * Reads a single block of 512 bytes at the given address into - * the given buffer and returns true on success, false otherwise. - * - * @param address address in 512 byte units - * @param block 512 byte buffer - * @return success - */ -bool readSingleBlock(uint32_t address, uint8_t *block); - -/** - * Reads multiple blocks of 512 bytes starting at the given address - * and, for each block, passes the buffer to the given function. - * By returning false, the function can request to stop reading blocks. - * - * @param address - * @param consume - * @return success - */ -bool readMultiBlock(uint32_t address, Consumer consume); - -/** - * Writes a single block of 512 bytes starting at the given address - * from the given buffer and returns true on success, false otherwise. - * - * @param address address in 512 byte units - * @param block 512 byte buffer - * @return success - */ -bool writeSingleBlock(uint32_t address, uint8_t *block); - -#endif /* SDCARD_H */ diff --git a/types.h b/types.h index 3203134..507847d 100644 --- a/types.h +++ b/types.h @@ -51,11 +51,5 @@ */ typedef void (*Function)(void); -/** - * Pointer to a function that takes an array of bytes - * and returns a boolean. - */ -typedef bool (*Consumer)(uint8_t*); - #endif /* TYPES_H */