//------------------------------------------------------------------------- // Titel : SD/MMC-Card-Basics // Sample W04 - myAVR Beispiel für MK3 Board // (mehr und ausfühlicher im SiSy-Projekt im Download unter www.myAVR.de) // title : SD/MMC-card-basics // sample W04 - myAVR sample for the MK3 board // (more details in the SiSy-project at download on www.myAVR.de) // //------------------------------------------------------------------------- // Prozessor : ATmega2560 // Takt : 16 MHz // Sprache : C // Datum : 15.04.2009 // Version : 1.0 // Autor : Christian Müller - myavr.de // Programmer: mySmartUSB MK3 //------------------------------------------------------------------------- // Funktion : Das Programm liest Daten per USART in einen Buffer ein, bis entweder ein "*" gesendet // wird oder mehr als 512 Byte gesendet wurden // Danach kann man mit Taster 1 auf dem MK3 Board die Daten auf die SD/MMC-Karte schreiben // Mit Taster 2 kann man einen Datenblock (512 Byte) von der SD/MMC-Karte lesen // Mit Taster 3 kann man den Buffer löschen (mit 0 füllen) und wieder zurück in den Datensendemodus gelangen // // ACHTUNG: Da SPI sowohl zum programmieren des Mikrocontrollers als auch zum für die Komunikation mit der SD/MMC-Karte benutzt wird, // sollte die SD/MMC-Karte während des Brennvorgangs NICHT eingelegt sein. Nach dem Brennvorgang kann die SD/MMC-Karte eingelegt werden, // ein manueller Reset des Programms ist dann aber notwendig um den reibungslosen Ablauf des Progamms sicherzustellen. // // function : the program recieve data from USART in a buffer, until a "*" is recieved or more as 512 bytes are recived // if data recieve is ready, the button 1 on the MK3 Board will save the data on the SD/MMC-card // button 2 read a block (512 byte) from the SD/MMC-card // button 3 will delete the data in the buffer (fill with 0) and goback to data recieve mode // // ATTENTION: SPI is use to programm the controller and also to communicate with the SD/MMC-card. it is recommended to insert the SD/MMC-card // during programming the controller. until programing instert the SD/MMC-card and reset the program manual to restart the program // // Schaltung : Quick-Connect "Button+Joy on Port K" und "LED on Port-L" auf dem MK3 Board // circuit : quick-connect "Button+Joy on Port K" and "LED on Port-L" at the MK3 board //------------------------------------------------------------------------- #define F_CPU 16000000 #define BAUD 19200 #include #include char uartGetChar(); //------------------------------------------------------------------------- //de: initialisiert das SPI, welches zum ansteuern der SD/MMC-Karte genutzt wird //eng: initialize the SPI, which is use to control the SD/MMC-card void sdInit(); //de: aktiviert SlaveSelect durch löschen von Bit0 (Low) an Port-B (SS=low aktiv) //eng: slaveselect active by clear bit0 (low) on port-B (SS=low activ) void sdSelectOn(); //de: deaktiviert SlaveSelect durch setzen von Bit0 (High) an Port-B (SS=low aktiv) //eng: slaveselect inactive by set bit0 (high) on port-B (SS=low activ) void sdSelectOff(); //de: startet die Übertragung, sendet die Daten und wartet auf Übertragungsende //de: PE: data = zu sendendes Byte //eng: start the transmission, send the data and wait for transmissionend //eng: PE: data = the byte to send uint8_t spiSendAndWait(uint8_t data); //de: sendet ein 6-Byte-Commando an die SD/MMC-Card //de: Setzt SlaveSelect = aktiv und lässt es aktiv. //de: PE: cmd = Zeiger auf erstes Byte des Kommandos //de: PA: SPI-Antwort nach dem Kommando, bei TimeOut = 0xff //eng: send a 6-byte command to the SD/MMC-card //eng: turn slaveselect to active, it will be active until function end //eng: PE: cmd = pointer to the first byte of the command //eng: PA: return from the SPI after the command is send, if timeout return is 0xff uint8_t sdWriteCommand(uint8_t* cmd); //de: liest einen Sektor der SD/MMC-Karte aus //de: PE: sector = Sektornummmer //de: buffer = Zeiger auf Speicher für die gelesenen Daten //de: bytes = Anzahl der zu lesenden Bytes (muß ganzer Sektor sein) //de: PA: Fehlercode //eng: read a sector from the SD/MMC-card //eng: PE: sector = sectornumber //eng: buffer = pointer to the readed data //eng: bytes = max. count of data (must be a full sectorlength) //eng: PA: errorcode bool sdReadSector(uint32_t sector, uint8_t *buffer, uint16_t bytes); //de: schreibt einen Sektor auf die SD/MMC-Karte //de: PE: sector = Sektornummmer //de: buffer = Zeiger auf Speicher für die Daten //de: bytes = Anzahl der zu lesenden Bytes (muß ganzer Sektor sein) //de: PA: Fehlercode //eng: write a sector to the SD/MMC-card //eng: PE: sector = sectornumber //eng: buffer = pointer to the data //eng: bytes = max. count of data (must be a full sectorlength) //eng: PA: errorcode bool sdWriteSector(uint32_t sector, uint8_t *buffer,uint16_t bytes); //--------------------- //de: initialisiert die USART //eng: initialize the USART void uartInit(); //de: sendet ein Byte an die USART //de: PE: data = das Byte //eng: send a byte on USART //eng: PE: data = the byte void uartPutChar(uint8_t data); //de: sendet eine Zeichenkette an die USART //de: PE: data = Zeiger zu der Zeichenkette //eng: send a string on USART //eng: PE: data = pointer to the string void uartPutString(const char* buffer); //de: initialisiert die Ports für die Taster //eng: initialize the ports for the buttons void portsInit(); //--------------------- //de: Variable für SPI ist initialsiert //eng: variable for SPI ist initialize bool isInit=false; //de: Variable für SPI letzter Fehler //eng: variable for SPI last error uint8_t lastError=0; //------------------------------------------------------------------------- //de: initialisiert das SPI, welches zum ansteuern der SD/MMC-Karte genutzt wird //eng: initialize the SPI, which is use to control the SD/MMC-card void spiInit() { //de: Port-B als Ausgang konfigurieren //eng: config port-B as output sbi(DDRB,0); //de: löschen von Bit0 an Port-B (SlaveSelect an) //eng: clear bit0 on port-B (slaveselect on) cbi(PORTB,0); //de: löschen von Bit3 an Port-B (MISO = Eingang) //eng: clear bit3 on port-B (MISO = input) cbi(DDRB,3); //de: setzten von Bit2 an Port-B (MOSI = Ausgang) //eng: set bit2 on port-B (MOSI = output) sbi(DDRB,2); //de: setzten von Bit1 an Port-B (SCK = Ausgang) //eng: set bit1 on port-B (SCK =output) sbi(DDRB,1); //de: SPI-Master setzen //eng: set SPI-master sbi(SPCR,MSTR); //de: SPI aktivieren //eng: activate SPI sbi(SPCR,SPE); //de: Verhältnis von SCK und OSC Frequenz = 1/16 //eng: relationship between SCK and OSC frequency = 1/16 SPCR|=0x01; isInit=true; } //--------------------- //de: aktiviert SlaveSelect durch löschen von Bit0 (Low) an Port-B (SS=low aktiv) //eng: slaveselect active by clear bit0 (low) on port-B (SS=low activ) void sdSelectOn() { //de: löschen von Bit0 an Port-B (SlaveSelect an) //eng: clear bit0 on port-B (slaveselect on) cbi(PORTB,0); } //--------------------- //de: deaktiviert SlaveSelect durch setzen von Bit0 (High) an Port-B (SS=low aktiv) //eng: slaveselect inactive by set bit0 (high) on port-B (SS=low activ) void sdSelectOff() { //de: setzten von Bit0 an Port-B (SlaveSelect aus) //eng: set bit0 on port-B (slaveselect off) sbi(PORTB,0); } //--------------------- //de: startet die Übertragung, sendet die Daten und wartet auf Übertragungsende //de: PE: data = zu sendendes Byte //eng: start the transmission, send the data and wait for transmissionend //eng: PE: data = the byte to send uint8_t spiSendAndWait(uint8_t data) { //de: Datenbyte in das SPI-Datenregister (Start der Übertragung) //eng: put the date in the SPI data register (start transmission) SPDR = data; //de: warten auf Übertragungsende (SPIF Flag ist gesetzt) //eng: wait until transmission end (SPIF flag is set) while(!(SPSR & 0x80)) {} //de: empfangenes Datenbyte zurück geben //eng: return the recived data return SPDR; } //--------------------- //de: initialisiert die USART //eng: initialize the USART void uartInit() { //de: Sender und Emfpänger aktivieren //eng: activate the tranmitter and the receiver UCSR1B = (1<>8; } //--------------------- //de: empfängt ein Byte von der USART //de: PA: das Byte //eng: receive a byte from USART //eng: PA: the byte char uartGetChar() { char data=0; //de: warte bis Empfang fertig //eng: wait until receive is complete while (!(UCSR1A&128)); //de: empfangen //eng: receive data=UDR1; return data; } //--------------------- //de: sendet ein Byte an die USART //de: PE: data = das Byte //eng: send a byte on USART //eng: PE: data = the byte void uartPutChar(uint8_t data) { //de: warten bis Senderegister leer ist //eng: wait until while (!(UCSR1A & 0x20)) {} //de: senden der Daten //eng: send Data UDR1=data; } //--------------------- //de: sendet eine Zeichenkette an die USART //de: PE: data = Zeiger zu der Zeichenkette //eng: send a string on USART //eng: PE: data = pointer to the string void uartPutString(const char* buffer) { uint8_t x; //de: je Zeichen //eng for each character while (x=buffer[0]) { //de: Zeichen senden //eng: send character uartPutChar(x); //de: nächstes Zeichen //eng: next character buffer++; } } //--------------------- //de: initialisiert das SPI, welches zum ansteuern der SD/MMC-Karte genutzt wird //eng: initialize the SPI, which is use to control the SD/MMC-card void sdInit() { bool ok=true; uint16_t timeout; //de: SD/MMC-Karte aktiv //eng: SD/MMC-card active sdSelectOn(); isInit=true; //de: Initialisiere SD/MMC-Karte in den SPI-Mode //eng: initialize SD/MMC-card to SPI-mode uint8_t n; //de: Sendet mindenstens 74+ Clocks an die SD/MMC-Karte //eng: send a minimum of 74+ clocks to the SD/MMC-card for (n = 0; n<0x0f; n++) { //de: senden der Daten //de: wenn das Programm hier hängen bleibt, ist kein Master-Mode initialisiert (oder SPI ist in Slave zurückgefallen) //eng: send data //eng: if the program is hang up here, master-mode is not initialized (or SPI is fall back to slave-mode) spiSendAndWait(0xff); } //de: sendet Kommando CMD0 an die SD/MMC-Karte //eng: send comand CMD0 to the SD/MMC-card uint8_t cmd[] = {0x40,0x00,0x00,0x00,0x00,0x95}; timeout=4000; //de: warten auf Leerlauf //eng: wait for idle while(sdWriteCommand(cmd) !=1) { if (!timeout--) { //de: wenn Fehler dann Abbruch //eng: if error then break lastError=1; ok=false; break; } } //de: sendet Kommando CMD1 an SD/MMC-Karte //eng: send comand CMD1 to the SD/MMC-card if(ok) { cmd[0] = 0x41; cmd[5] = 0xFF; timeout = 4000; //de: warten auf Fertig //eng: wait for ready while( sdWriteCommand(cmd) !=0) { if (!timeout--) { //de: wenn Fehler dann Abbruch //eng: if error then break lastError=2; ok=false; break; } } } //de: SD/MMC-Karte inaktiv //eng: deactivate SD/MMC-card sdSelectOff(); isInit=ok; } //--------------------- //de: sendet ein 6-Byte-Commando an die SD/MMC-Card //de: Setzt SlaveSelect = aktiv und lässt es aktiv. //de: PE: cmd = Zeiger auf erstes Byte des Kommandos //de: PA: SPI-Antwort nach dem Kommando, bei TimeOut = 0xff //eng: send a 6-byte command to the SD/MMC-card //eng: turn slaveselect to active, it will be active until function end //eng: PE: cmd = pointer to the first byte of the command //eng: PA: return from the SPI after the command is send, if timeout return is 0xff uint8_t sdWriteCommand(uint8_t* cmd) { /* Responce Format R1 (Bit High=Error) • bit0 = In idle state: The card is in idle state and running the initializing process. • bit1 = Erase reset: An erase sequence was cleared before executing because an out of erase sequencecommand was received. • bit2 = Illegal command: An illegal command code was detected. • bit3 = Communication CRC error: The CRC check of the last command failed. • bit4 = Erase sequence error: An error in the sequence of erase commands occurred. • bit5 = Address error: A misaligned address that did not match the block length was used in the command. • bit6 = Parameter error: The command’s argument (e.g. address, block length) was outside the allowed range for this card. • bit7 = 0 */ uint8_t ret; if(!isInit) { return 0xff; } //de: SD/MMC-Karte inaktiv //eng: deactivate SD/MMC-card sdSelectOff(); //de: sendet 8 Clock Impulse //eng: send 8 clock impuls spiSendAndWait(0xFF); //de: SD/MMC-Karte aktiv //eng: activate SD/MMC-card sdSelectOn(); //de: sendet das 6 Byte Kommando //eng: send the 6 Byte Kommando uint8_t n; uint8_t last; for (n = 0;n<6;n++) { last=spiSendAndWait(cmd[0]); cmd++; } //de: wartet auf eine gültige Antwort von der SD/MMC-Karte //eng: wait for a valid answer from the SD/MMC-card uint16_t timeout = 500; while ( (ret=spiSendAndWait(0xff)) == 0xff) { if (!timeout--) //de: Abbruch da die SD/MMC-Karte nicht Antwortet //eng: no answer = break break; } //de: Rückgabe festlegen: 0xFF = ok; alles andere =Fehler //eng: return: 0xFF = ok; all other = error if(ret==0xff && !lastError) lastError=0xFF; } //--------------------- //de: liest einen Sektor der SD/MMC-Karte aus //de: PE: sector = Sektornummmer //de: buffer = Zeiger auf Speicher für die gelesenen Daten //de: bytes = Anzahl der zu lesenden Bytes (muß ganzer Sektor sein) //eng: read a sector from the SD/MMC-card //eng: PE: sector = sectornumber //eng: buffer = pointer to the readed data //eng: bytes = max. count of data (must be a full sectorlength) bool sdReadSector(uint32_t sector, uint8_t *buffer,uint16_t bytes) { bool ok=true; //de: Kommando 17 für SD/MMC-Karte (lese Block) //eng: comand 17 for the SD/MMC-card (read block) uint8_t cmd[] = {0x51,0x00,0x00,0x00,0x00,0xFF}; //de: die Sektoradresse auf der SD/MMC-Karte in Bytes //de: die Adresse wird umgerechnet und in das Kommando eingefügt //eng: the sectoraddress on the SD/MMC-card //eng: the address will be convert and included to the comand sector = sector << 9; cmd[1] = ((sector & 0xFF000000) >>24 ); cmd[2] = ((sector & 0x00FF0000) >>16 ); cmd[3] = ((sector & 0x0000FF00) >>8 ); //de: sendet das Kommando an SD/MMC-Karte //eng: send the comand to the SD/MMC-card if (sdWriteCommand (cmd) != 0) ok=false; uint8_t last; if(ok) { // de: wartet auf Start Byte von der SD/MMC-Karte // eng: wait for start byte from the SD/MMC-card uint16_t ww=5000; while (last=spiSendAndWait(0xff) != 0xFE) { if(!ww) { //de: Timeout bei: Warte auf Start Byte //de: timeout while: warte auf start byte ok=false; break; } ww--; } } //de: lesen des Blocks (normal 512 Bytes) von MMC/SD-Karte //eng: read the block (normal 512 bytes) from the SD/MMC-card if(ok) { uint16_t n; for (n=0;n>24 ); cmd[2] = ((sector & 0x00FF0000) >>16 ); cmd[3] = ((sector & 0x0000FF00) >>8 ); //de: sendet das Kommando an SD/MMC-Karte //eng: send the comand to the SD/MMC-card if (sdWriteCommand (cmd) != 0) ok=false; //de: wartet einen Moment und sendet Clocks an die SD/MMC-Karte //eng: wait a short and send clocks to the SD/MMC-card if(ok) { for (uint8_t n=0; n<100; n++) { spiSendAndWait(0xFF); } } //de: sendet das Start Byte an SD/MMC-Karte //eng: send the start byte to the SD/MMC-card if(ok) spiSendAndWait(0xFE); //de: schreiben des Blocks auf die SD/MMC-Karte //eng: write the block to the SD/MMC-card if(ok) { for (uint16_t n = 0; n < bytes; n++) { spiSendAndWait(buffer[n]); } } //de: CRC-Byte schreiben //eng: write CRC-byte if(ok) { //de: Schreibe Dummy CRC, CRC Code wird nicht benutzt //eng: write dummy CRC, CRC code is not used spiSendAndWait(0xFF); spiSendAndWait(0xFF); } if(ok) { //de: wartet auf SD/MMC-Karte //eng: wait for the SD/MMC-card while (spiSendAndWait(0xff) != 0xff) {} } //de: SD/MMC-Karte inaktiv //eng: deactivate SD/MMC-card sdSelectOff(); return ok; } //--------------------- //de: Ports konfigurieren für Taster und LEDs //eng: config ports for buttons and LEDs void portsInit() { DDRK=0x00; PORTK=0xFF; DDRL=0xFF; } ///////////////////////////////////////////////////////////////////////////// // Main-Funktion ///////////////////////////////////////////////////////////////////////////// uint8_t buffer[512]={0}; int main() { bool ok=false; bool stop=false; //de: Initialisierung uartInit(); spiInit(); portsInit(); sdInit(); if(lastError) uartPutString("sd-card error\n"); else uartPutString("sd-card ok\n"); int x=0; //////////////////////////////////////////////////////////////// ////////////////////////////mainloop//////////////////////////// //////////////////////////////////////////////////////////////// while(true) { //de: warte auf Daten, endet nur bei mehr als 512 Byte oder bei '*' //eng: wait for data, end only by recieve a "*" or more than 512 bytes while(!stop) { PORTL=128; //de: solang Empfangsregister nicht leer //eng: while receive register not empty while((UCSR1A & (1<512)) { stop=true; } } } //de: wenn Taster 1 gedrückt (Block schreiben) //eng: if button 1 pushed (write block) if(~PINK & 0x01) { PORTL=2; //de: Block schreiben //eng: write block ok=sdWriteSector(0,&buffer[0],512); //de: Auswertung //eng: report if(!ok) { uartPutString("error write Block\n"); } else { uartPutString("write Block ok \n"); } } //de: wenn Taster 2 gedrückt (Block lesen) //eng: if button 2 pushed (read block) else if(~PINK & 0x02) { PORTL=4; //de: Buffer mit 0 füllen, um sicher zu stellen das man das gelesene erkennt //eng: fill the buffer with 0, to see the change memset(buffer,0,512); //de: Block lesen //eng: read block ok=sdReadSector(0,&buffer[0],512); //de: Auswertung //eng: report if(!ok) { uartPutString("error read Block\n"); } else { uartPutString("read Block ok:\n"); //de: Buffer an USART senden //eng: send the buffer to USART uartPutString((char*)buffer); //de: Enter am Ende //eng: line feed on end uartPutChar('\n'); } } //de: wenn Taster 3 gedrückt (Buffer mit 0 füllen und wieder auf Daten warten) //eng: if button 3 pushed (fill buffer with 0 and go back to to wait for USART data) else if(~PINK & 0x04) { PORTL=8; //de: Buffer mit 0 füllen //eng: fill buffer with 0 memset(buffer,0,512); //de: auf Daten warten wieder aktivieren //eng: activate data recieve from USART stop=false; //de: Zähler zurück auf Anfang //eng: counter back to begin x=0; } //de: wenn nichts gedrückt //eng: if nothing pushed else { PORTL=1; } //de: eine 1/2 sek warten //eng: wait 1/2 sec waitMs(500); } return 0; }