diff options
author | matt | 2008-09-17 00:13:22 +0000 |
---|---|---|
committer | matt | 2008-09-17 00:13:22 +0000 |
commit | ad482436a7c9e97f4bc1f7407dccd85a4cade6c5 (patch) | |
tree | 32fba3bce81649a98aa6b218cea07dc359c831d9 /usrp2/firmware/lib | |
parent | e2472717aff8c1f73f78eda2aa851a016dc9851a (diff) | |
download | gnuradio-ad482436a7c9e97f4bc1f7407dccd85a4cade6c5.tar.gz gnuradio-ad482436a7c9e97f4bc1f7407dccd85a4cade6c5.tar.bz2 gnuradio-ad482436a7c9e97f4bc1f7407dccd85a4cade6c5.zip |
firmware support for reading and writing the SD card
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9588 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'usrp2/firmware/lib')
-rw-r--r-- | usrp2/firmware/lib/Makefile.am | 2 | ||||
-rw-r--r-- | usrp2/firmware/lib/memory_map.h | 2 | ||||
-rw-r--r-- | usrp2/firmware/lib/sd.c | 197 | ||||
-rw-r--r-- | usrp2/firmware/lib/sd.h | 122 |
4 files changed, 322 insertions, 1 deletions
diff --git a/usrp2/firmware/lib/Makefile.am b/usrp2/firmware/lib/Makefile.am index 83dd915c9..a6dd47f6c 100644 --- a/usrp2/firmware/lib/Makefile.am +++ b/usrp2/firmware/lib/Makefile.am @@ -49,6 +49,7 @@ libu2fw_a_SOURCES = \ print_fxpt.c \ print_buffer.c \ printf.c \ + sd.c \ spi.c \ u2_init.c @@ -79,6 +80,7 @@ noinst_HEADERS = \ nonstdio.h \ pic.h \ print_rmon_regs.h \ + sd.h \ spi.h \ stdint.h \ stdio.h \ diff --git a/usrp2/firmware/lib/memory_map.h b/usrp2/firmware/lib/memory_map.h index 7dce59d03..88efcb9ac 100644 --- a/usrp2/firmware/lib/memory_map.h +++ b/usrp2/firmware/lib/memory_map.h @@ -569,7 +569,7 @@ typedef struct { #define SDSPI_BASE 0xEC00 typedef struct { - volatile uint32_t status; + volatile uint32_t status; // Write a 1 or 0 for controlling CS volatile uint32_t clkdiv; volatile uint32_t send_dat; volatile uint32_t receive_dat; diff --git a/usrp2/firmware/lib/sd.c b/usrp2/firmware/lib/sd.c new file mode 100644 index 000000000..d000b28ae --- /dev/null +++ b/usrp2/firmware/lib/sd.c @@ -0,0 +1,197 @@ +/* -*- c -*- */ +/* + * Copyright 2008 Ettus Research LLC + * + * 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/>. + */ + +#include "sd.h" +#include "memory_map.h" +#include "stdint.h" +#include "stdio.h" + +static inline void +sd_packarg(unsigned char *argument,unsigned int value) +{ + argument[3] = (unsigned char)(value >> 24); + argument[2] = (unsigned char)(value >> 16); + argument[1] = (unsigned char)(value >> 8); + argument[0] = (unsigned char)(value); +} + +int +sd_init(void) +{ + unsigned char response[5]; + unsigned char argument[4]; + int i,j; + + for(i=0;i<4;i++) + argument[i] = 0; + + // Set clock to less than 400 kHz to start out + sdspi_regs->clkdiv = 128; + + // Delay at least 74 cycles + sd_assert_cs(); + for(i = 0; i < 100; i++) + sd_send_byte(SD_IDLE); + sd_deassert_cs(); + + // Initialization Sequence -- CMD0 CMD55 ACMD41 CMD58 + // Put card in idle state + if(sd_send_command(SD_CMD0,SD_CMD0_R,response,argument)==0) + return 0; // Something went wrong in command + + j = 0; + do { + j++; + if(sd_send_command(SD_CMD55,SD_CMD55_R,response,argument)==1) + sd_send_command(SD_ACMD41,SD_ACMD41_R,response,argument); + else + j = SD_IDLE_WAIT_MAX; + } + while(((response[0] & SD_MSK_IDLE) == SD_MSK_IDLE) && (j < SD_IDLE_WAIT_MAX)); + + if(j>= SD_IDLE_WAIT_MAX) // IDLE timeout exceeded, card asleep + return 0; + + // CMD58 reads the SD card capabilities + if(sd_send_command(SD_CMD58,SD_CMD58_R,response,argument)==0) + return 0; // CMD58 FAIL + + if((response[2] & SD_MSK_OCR_33) != SD_MSK_OCR_33) + return 0; // Card doesn't do 3.3V + + //printf("OCR = %x %x %x %x\n",response[0],response[1],response[2],response[3]); + + // Set blocklen here + sd_packarg(argument,SD_BLOCKLEN); + if(sd_send_command(SD_CMD16,SD_CMD16_R,response,argument)==0) + return 0; // Set Blocklen failed + + // Reset back to high speed + sdspi_regs->clkdiv = 4; + //puts("finished init\n"); + return 1; +} + +int sd_send_command(unsigned char cmd,unsigned char response_type, + unsigned char *response,unsigned char *argument) +{ + int i; + char response_length; + unsigned char tmp; + + sd_assert_cs(); + sd_send_byte((cmd & 0x3F) | 0x40); + for(i=3;i>=0;i--) + sd_send_byte(argument[i]); + sd_send_byte(SD_CRC); // Always the same + + response_length = 0; + switch(response_type) + { + case SD_R1: + case SD_R1B: + response_length = 1; + break; + case SD_R2: + response_length = 2; + break; + case SD_R3: + response_length = 5; + break; + default: + break; + } + + // Wait for a response, which will have a 0 start bit + i = 0; + do + { + tmp = sd_rcv_byte(); + i++; + } + while(((tmp & 0x80) != 0) && i < SD_CMD_TIMEOUT); + + if(i>= SD_CMD_TIMEOUT) + { + sd_deassert_cs(); + //puts("cmd send timeout\n"); + return 0; + } + + for(i=response_length-1; i>=0; i--) + { + response[i] = tmp; + tmp = sd_rcv_byte(); + } + i = 0; + if(response_type == SD_R1B) + { + do + { + i++; + tmp = sd_rcv_byte(); + } + while(tmp != SD_IDLE); + sd_send_byte(SD_IDLE); + } + + //puts("send cmd success\n"); + sd_deassert_cs(); + return 1; +} + +int +sd_read_block (unsigned int blockaddr, unsigned char *buf) +{ + unsigned char response[5]; + unsigned char argument[4]; + unsigned int i = 0; + unsigned char tmp; + + blockaddr <<= SD_BLOCKLEN_NBITS; + sd_packarg(argument,blockaddr); + if(sd_send_command(SD_CMD17,SD_CMD17_R,response,argument)==0) + return 0; //Failed READ; + if(response[0] != 0) + return 0; //Misaligned READ + + sd_assert_cs(); + i = 0; + do + { + tmp = sd_rcv_byte(); + i++; + } + while((tmp == 0xFF) && (i < SD_RD_TIMEOUT)); + if((i>= SD_RD_TIMEOUT) ||((tmp & SD_MSK_TOK_DATAERROR) == 0)) + { + sd_send_byte(SD_IDLE); // Send a dummy before quitting + return 0; // Data ERROR + } + for(i=0;i<SD_BLOCKLEN;i++) + buf[i] = sd_rcv_byte(); + return 1; + +} + +int +sd_write_block(unsigned int blockaddr, const unsigned char *buf) +{ + // FIXME not implemented yet + return 0; +} diff --git a/usrp2/firmware/lib/sd.h b/usrp2/firmware/lib/sd.h new file mode 100644 index 000000000..e2d0ae38e --- /dev/null +++ b/usrp2/firmware/lib/sd.h @@ -0,0 +1,122 @@ +/* -*- c -*- */ +/* + * Copyright 2008 Ettus Research LLC + * + * 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/>. + */ + +#ifndef INCLUDED_SD_H +#define INCLUDED_SD_H + +#include "memory_map.h" + +#define SD_READY 1 +#define SD_IDLE_WAIT_MAX 100 +#define SD_CMD_TIMEOUT 100 +#define SD_RD_TIMEOUT 1000 + +#define SD_CMD0 0 +#define SD_CMD1 1 +#define SD_CMD9 9 +#define SD_CMD10 10 +#define SD_CMD12 12 +#define SD_CMD13 13 +#define SD_CMD16 16 +#define SD_CMD17 17 +#define SD_CMD18 18 +#define SD_CMD24 24 +#define SD_CMD25 25 +#define SD_CMD27 27 +#define SD_CMD28 28 +#define SD_CMD29 29 +#define SD_CMD30 30 +#define SD_CMD32 32 +#define SD_CMD33 33 +#define SD_CMD38 38 +#define SD_CMD55 55 +#define SD_CMD58 58 +#define SD_CMD59 59 +#define SD_ACMD41 41 +#define SD_IDLE 0xFF +#define SD_CRC 0x95 + +#define SD_R1 1 +#define SD_R1B 2 +#define SD_R2 3 +#define SD_R3 4 + +#define SD_CMD0_R SD_R1 +#define SD_CMD16_R SD_R1 +#define SD_CMD17_R SD_R1 +#define SD_CMD55_R SD_R1 +#define SD_ACMD41_R SD_R1 +#define SD_CMD58_R SD_R3 + +#define SD_BLOCKLEN 512 +#define SD_BLOCKLEN_NBITS 9 + +#define SD_MSK_IDLE 0x01 +#define SD_MSK_OCR_33 0xC0 +#define SD_MSK_TOK_DATAERROR 0xE0 + + +int sd_init(void); + +static inline void +sd_assert_cs(void) +{ + // Wait for idle before doing anything + while(sdspi_regs->status != SD_READY) + ; + sdspi_regs->status = 1; +} + +static inline void +sd_deassert_cs(void) +{ + // Wait for idle before doing anything + while(sdspi_regs->status != SD_READY) + ; + sdspi_regs->status = 0; +} + +static inline char +sd_rcv_byte(void) +{ + // Wait for idle before doing anything + while(sdspi_regs->status != SD_READY) + ; + sdspi_regs->send_dat = SD_IDLE; + while(sdspi_regs->status != SD_READY) + ; + return sdspi_regs-> receive_dat; +} + +static inline void +sd_send_byte(char dat) +{ + // Wait for idle before doing anything + while(sdspi_regs->status != SD_READY) + ; // Wait for status = 1 (ready) + sdspi_regs->send_dat = dat; +} + + +int sd_send_command(unsigned char cmd,unsigned char response_type, + unsigned char *response,unsigned char *argument); + +int sd_read_block (unsigned int blockaddr, unsigned char *buf); +int sd_write_block(unsigned int blockaddr, const unsigned char *buf); + +#endif /* INCLUDED_SD_H */ |