// ********************************************* // SD Card Reader - Savage16 implementation // with FAT32 file system // ********************************************* // List of SD Commands alias GO_IDLE_STATE 00 alias SEND_OP_COND 01 alias CHECK_V2_COMPLIANT 08 alias SEND_CSD 09 alias STOP_TRANSMISSION 12 alias SEND_STATUS 13 alias SET_BLOCK_LEN 16 alias READ_SINGLE_BLOCK 17 alias READ_MULTIPLE_BLOCKS 18 alias WRITE_SINGLE_BLOCK 24 alias WRITE_MULTIPLE_BLOCKS 25 alias ERASE_BLOCK_START_ADDR 32 alias ERASE_BLOCK_END_ADDR 33 alias ERASE_SELECTED_BLOCKS 38 alias SD_SEND_OP_COND 41 alias APP_CMD 55 alias CRC_ON_OFF 59 // SPI Clock Frequency alias 150kHz 165 alias 12.5Mhz 1 // Variables alias spdr r0 // I/O Data register for the SPI alias temp r1 alias cmd r2 // Command code to be send alias arg1 r6 // Arguments of the command alias arg2 r7 alias arg3 r8 alias arg4 r9 alias retry r3 alias resp r4 // Response of functions - 1 = OK, 0 = ERROR alias afis r5 // Data viewed on the display - for debugging alias addr_high r10 // High byte of the block address - max 0x7f alias addr_low r11 // Low word of the block address - max 0xffff // so max is 0x7fffff x 512B per block = 4 GB // I/O Control alias din pina alias dout porta alias assert portc alias ss portb alias speed portd // fCLK = 50MHz / 2*(speed+1) alias done pinb // main() // ***************************************************************************************** jmp start // jump to start of program ret // interrupt vector table ret ret ret ret // 1 Hz Timer ret // 44.100 kHz Timer ret // Transmit_complete from SPI interface ret ret ret ret ret ret ret ret ret label start // start of program clr sf, if // Work in Unsigned Integer mode // and Disable Interrupt System mov afis, 0 call delay // wait 100ms for VCC stabilisation out speed, 150kHz // Low speed at init call card_init // Initialize the SD Card out speed, 12.5Mhz // High speed normal comm mov addr_low, 0 mov addr_high, 0 call read_block // Read the MBR mov afis, resp // Display if everything OK stop // Stop execution of the program // ***************************************************************************************** // resp = Read_Block(addr_high, addr_low) // ***************************************************************************************** label read_block // Reads a single block from the SD Card pushf push temp shl addr_high, 9 shr temp, addr_low, 7 or addr_high, temp shl addr_low, 9 pop temp mov cmd, READ_SINGLE_BLOCK mov arg1, 0 mov arg2, 0 mov arg3, 0 mov arg4, 0 call send_command test resp jnz exit_read_block out assert, 0 mov retry, 0 label retry_get_token inc retry cmp retry, 0xfff je exit_read_block call spi_receive cmp spdr, 0xfe jne retry_get_token mov retry, 0 label block_loop call spi_receive store spdr, retry inc retry cmp retry, 512 jne block_loop call spi_receive call spi_receive call spi_receive out assert, 1 mov resp, 1 popf ret label exit_read_block mov resp, 0 popf ret // return from the function // ***************************************************************************************** // resp = Card_init() // ***************************************************************************************** label card_init // Initializes the SD Card pushf mov temp, 0 label for_count_10 push temp call spi_receive pop temp inc temp cmp temp, 10 jl for_count_10 mov cmd, GO_IDLE_STATE mov arg1, 0 mov arg2, 0 mov arg3, 0 mov arg4, 0 mov retry, 0 label retry_init_card inc retry cmp retry, 0xff je exit_card_init call send_command cmp resp, 0x01 jne retry_init_card call spi_receive call spi_receive //mov cmd, CHECK_V2_COMPLIANT //mov arg1, 0 //mov arg2, 0 //mov arg3, 0x01 //mov arg4, 0xaa //mov crc, 0x87 mov retry, 0 label retry_init_card_2 inc retry cmp retry, 0xff je exit_card_init mov cmd, APP_CMD call send_command mov cmd, SD_SEND_OP_COND call send_command test resp jnz retry_init_card_2 mov cmd, SET_BLOCK_LEN mov arg3, 0x02 mov retry, 0 label retry_init_card3 inc retry cmp retry, 0xff je exit_card_init call send_command test resp jnz retry_init_card3 mov resp, 1 popf ret label exit_card_init mov resp, 0 popf ret // return from the function // ***************************************************************************************** // resp = Send_Command(cmd) // ***************************************************************************************** label send_command // Sends a raw command to the SD Card pushf push retry or cmd, 0x40 out assert, 0 mov spdr, cmd call spi_transmit mov spdr, arg1 call spi_transmit mov spdr, arg2 call spi_transmit mov spdr, arg3 call spi_transmit mov spdr, arg4 call spi_transmit mov spdr, 0x95 call spi_transmit mov retry, 0 label retry_send_command cmp retry, 0xff je exit_send_command call spi_receive inc retry cmp spdr, 0xff je retry_send_command label exit_send_command mov resp, spdr // the response from the SD card //store spdr, 0 //call spi_receive //store spdr, 1 //call spi_receive //store spdr, 2 //call spi_receive //store spdr, 3 //call spi_receive //store spdr, 4 out assert, 1 call spi_receive call spi_receive pop retry popf ret // return from the function // SPI_Transmit() // ***************************************************************************************** label spi_transmit // Transmits one byte of data (SPDR) over the SPI pushf // push the flags in the stack out dout, spdr out ss, 0 // activates the SPI transmission label wait_transmit // wait until DONE pin is high in temp, done cmp temp, 1 jne wait_transmit out ss, 1 // deactivates the SPI transmission popf // extract the flags from the stack ret // return from the function // ***************************************************************************************** // SPI_Receive() // ***************************************************************************************** label spi_receive // Receives one byte of data (SPDR) over the SPI pushf // push the flags in the stack out dout, 0xff out ss, 0 // activates the SPI reception label wait_receive // wait until DONE pin is high in temp, done cmp temp, 1 jne wait_receive out ss, 1 // deactivates the SPI reception in spdr, din popf // extract the flags from the stack ret // return from the function // ***************************************************************************************** // Delay(100ms) // ***************************************************************************************** label delay // 100ms Delay function pushf // push the flags in the stack push r5 push r6 push temp mov temp, 0 label wait_delay div r5, 1 // 19 clocks for a dummy division div r5, 1 // 19 clocks for a dummy division div r5, 1 // 19 clocks for a dummy division div r5, 1 // 19 clocks for a dummy division inc temp cmp temp, 0xffff // loop for 65536 times jne wait_delay // that's aprox 80 x 65536 = 5 Mclocks // the clock freq is 50 Mhz // so we delay for aprox 1/10 of a second pop temp pop r6 pop r5 popf // extract the flags from the stack ret // return from the function // *****************************************************************************************