mirror of
https://github.com/marqs85/ossc.git
synced 2026-04-21 05:16:31 +00:00
SD SPI implementation finished
This commit is contained in:
@@ -13,7 +13,8 @@
|
||||
#define _INTEGER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <typedef.h>
|
||||
#if 0
|
||||
/* 16-bit, 32-bit or larger integer */
|
||||
typedef int16_t INT;
|
||||
typedef uint16_t UINT;
|
||||
@@ -37,8 +38,8 @@ typedef uint32_t DWORD;
|
||||
|
||||
/* Boolean type */
|
||||
typedef enum { FALSE = 0, TRUE } BOOLEAN;
|
||||
#endif
|
||||
typedef enum { LOW = 0, HIGH } THROTTLE;
|
||||
|
||||
#endif
|
||||
|
||||
// «integer.h» is part of:
|
||||
|
||||
@@ -109,6 +109,7 @@ void __SD_Speed_Transfer(BYTE throttle) {
|
||||
|
||||
BYTE __SD_Send_Cmd(BYTE cmd, DWORD arg)
|
||||
{
|
||||
BYTE wiredata[10];
|
||||
BYTE crc, res;
|
||||
// ACMD«n» is the command sequense of CMD55-CMD«n»
|
||||
if(cmd & 0x80) {
|
||||
@@ -118,29 +119,29 @@ BYTE __SD_Send_Cmd(BYTE cmd, DWORD arg)
|
||||
}
|
||||
|
||||
// Select the card
|
||||
__SD_Deassert();
|
||||
SPI_RW(0xFF);
|
||||
__SD_Assert();
|
||||
SPI_RW(0xFF);
|
||||
|
||||
|
||||
// Send complete command set
|
||||
SPI_RW(cmd); // Start and command index
|
||||
SPI_RW((BYTE)(arg >> 24)); // Arg[31-24]
|
||||
SPI_RW((BYTE)(arg >> 16)); // Arg[23-16]
|
||||
SPI_RW((BYTE)(arg >> 8 )); // Arg[15-08]
|
||||
SPI_RW((BYTE)(arg >> 0 )); // Arg[07-00]
|
||||
wiredata[0] = cmd; // Start and command index
|
||||
wiredata[1] = (arg >> 24); // Arg[31-24]
|
||||
wiredata[2] = (arg >> 16); // Arg[23-16]
|
||||
wiredata[3] = (arg >> 8 ); // Arg[15-08]
|
||||
wiredata[4] = (arg >> 0 ); // Arg[07-00]
|
||||
|
||||
// CRC?
|
||||
crc = 0x01; // Dummy CRC and stop
|
||||
if(cmd == CMD0) crc = 0x95; // Valid CRC for CMD0(0)
|
||||
if(cmd == CMD8) crc = 0x87; // Valid CRC for CMD8(0x1AA)
|
||||
SPI_RW(crc);
|
||||
wiredata[5] = crc;
|
||||
|
||||
SPI_W(wiredata, 6);
|
||||
|
||||
// Receive command response
|
||||
// Wait for a valid response in timeout of 5 milliseconds
|
||||
SPI_Timer_On(5);
|
||||
do {
|
||||
res = SPI_RW(0xFF);
|
||||
SPI_R(&res, 1);
|
||||
} while((res & 0x80)&&(SPI_Timer_Status()==TRUE));
|
||||
SPI_Timer_Off();
|
||||
// Return with the response value
|
||||
@@ -185,8 +186,8 @@ SDRESULTS __SD_Write_Block(SD_DEV *dev, void *dat, BYTE token)
|
||||
|
||||
DWORD __SD_Sectors (SD_DEV *dev)
|
||||
{
|
||||
BYTE csd[16];
|
||||
BYTE idx;
|
||||
BYTE csd[18];
|
||||
BYTE tkn;
|
||||
DWORD ss = 0;
|
||||
WORD C_SIZE = 0;
|
||||
BYTE C_SIZE_MULT = 0;
|
||||
@@ -194,12 +195,18 @@ DWORD __SD_Sectors (SD_DEV *dev)
|
||||
if(__SD_Send_Cmd(CMD9, 0)==0)
|
||||
{
|
||||
// Wait for response
|
||||
while (SPI_RW(0xFF) == 0xFF);
|
||||
for (idx=0; idx!=16; idx++) csd[idx] = SPI_RW(0xFF);
|
||||
// Dummy CRC
|
||||
SPI_RW(0xFF);
|
||||
SPI_RW(0xFF);
|
||||
SPI_Release();
|
||||
SPI_Timer_On(5); // Wait for data packet (timeout of 5ms)
|
||||
do {
|
||||
SPI_R(&tkn, 1);
|
||||
} while((tkn==0xFF)&&(SPI_Timer_Status()==TRUE));
|
||||
SPI_Timer_Off();
|
||||
|
||||
if(tkn!=0xFE)
|
||||
return 0;
|
||||
|
||||
// TODO: CRC check
|
||||
SPI_R(csd, 18);
|
||||
|
||||
if(dev->cardtype & SDCT_SD1)
|
||||
{
|
||||
ss = csd[0];
|
||||
@@ -225,12 +232,15 @@ DWORD __SD_Sectors (SD_DEV *dev)
|
||||
C_SIZE <<= 8;
|
||||
C_SIZE |= (csd[9] & 0xFF);
|
||||
// C_SIZE_MULT [--]. don't exits
|
||||
C_SIZE_MULT = 0;
|
||||
C_SIZE_MULT = 17; //C_SIZE_MULT+2 = 19
|
||||
printf("csize: %u\n", C_SIZE);
|
||||
}
|
||||
ss = (C_SIZE + 1);
|
||||
ss *= __SD_Power_Of_Two(C_SIZE_MULT + 2);
|
||||
ss *= __SD_Power_Of_Two(READ_BL_LEN);
|
||||
ss /= SD_BLK_SIZE;
|
||||
// SD_BLK_SIZE = 2^9
|
||||
//ss *= __SD_Power_Of_Two(C_SIZE_MULT + 2 + READ_BL_LEN - 9);
|
||||
ss *= 1 << (C_SIZE_MULT + 2 + READ_BL_LEN - 9);
|
||||
//ss /= SD_BLK_SIZE;
|
||||
printf("ss: %u\n", ss);
|
||||
return (ss);
|
||||
} else return (0); // Error
|
||||
}
|
||||
@@ -242,6 +252,7 @@ DWORD __SD_Sectors (SD_DEV *dev)
|
||||
|
||||
SDRESULTS SD_Init(SD_DEV *dev)
|
||||
{
|
||||
BYTE initdata[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
#if defined(_M_IX86) // x86
|
||||
dev->fp = fopen(dev->fn, "r+");
|
||||
if (dev->fp == NULL)
|
||||
@@ -265,67 +276,68 @@ SDRESULTS SD_Init(SD_DEV *dev)
|
||||
// Initialize SPI for use with the memory card
|
||||
SPI_Init();
|
||||
|
||||
SPI_CS_High();
|
||||
__SD_Deassert();
|
||||
SPI_Freq_Low();
|
||||
|
||||
// 80 dummy clocks
|
||||
for(idx = 0; idx != 10; idx++) SPI_RW(0xFF);
|
||||
//for(idx = 0; idx != 10; idx++) SPI_RW(0xFF);
|
||||
SPI_W(initdata, sizeof(initdata));
|
||||
|
||||
SPI_Timer_On(500);
|
||||
/*SPI_Timer_On(500);
|
||||
while(SPI_Timer_Status()==TRUE);
|
||||
SPI_Timer_Off();
|
||||
SPI_Timer_Off();*/
|
||||
|
||||
dev->mount = FALSE;
|
||||
SPI_Timer_On(500);
|
||||
while ((__SD_Send_Cmd(CMD0, 0) != 1)&&(SPI_Timer_Status()==TRUE));
|
||||
SPI_Timer_Off();
|
||||
// Idle state
|
||||
if (__SD_Send_Cmd(CMD0, 0) == 1) {
|
||||
// SD version 2?
|
||||
if (__SD_Send_Cmd(CMD8, 0x1AA) == 1) {
|
||||
// Get trailing return value of R7 resp
|
||||
for (n = 0; n < 4; n++) ocr[n] = SPI_RW(0xFF);
|
||||
// VDD range of 2.7-3.6V is OK?
|
||||
if ((ocr[2] == 0x01)&&(ocr[3] == 0xAA))
|
||||
{
|
||||
// Wait for leaving idle state (ACMD41 with HCS bit)...
|
||||
SPI_Timer_On(1000);
|
||||
while ((SPI_Timer_Status()==TRUE)&&(__SD_Send_Cmd(ACMD41, 1UL << 30)));
|
||||
SPI_Timer_Off();
|
||||
// CCS in the OCR?
|
||||
if ((SPI_Timer_Status()==TRUE)&&(__SD_Send_Cmd(CMD58, 0) == 0))
|
||||
{
|
||||
for (n = 0; n < 4; n++) ocr[n] = SPI_RW(0xFF);
|
||||
// SD version 2?
|
||||
ct = (ocr[0] & 0x40) ? SDCT_SD2 | SDCT_BLOCK : SDCT_SD2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// SD version 1 or MMC?
|
||||
if (__SD_Send_Cmd(ACMD41, 0) <= 1)
|
||||
{
|
||||
// SD version 1
|
||||
ct = SDCT_SD1;
|
||||
cmd = ACMD41;
|
||||
} else {
|
||||
// MMC version 3
|
||||
ct = SDCT_MMC;
|
||||
cmd = CMD1;
|
||||
}
|
||||
// Wait for leaving idle state
|
||||
SPI_Timer_On(250);
|
||||
while((SPI_Timer_Status()==TRUE)&&(__SD_Send_Cmd(cmd, 0)));
|
||||
|
||||
// SD version 2?
|
||||
if (__SD_Send_Cmd(CMD8, 0x1AA) == 1) {
|
||||
// Get trailing return value of R7 resp
|
||||
SPI_R(ocr, 4);
|
||||
// VDD range of 2.7-3.6V is OK?
|
||||
if ((ocr[2] == 0x01)&&(ocr[3] == 0xAA))
|
||||
{
|
||||
// Wait for leaving idle state (ACMD41 with HCS bit)...
|
||||
SPI_Timer_On(1000);
|
||||
while ((SPI_Timer_Status()==TRUE)&&(__SD_Send_Cmd(ACMD41, 1UL << 30)));
|
||||
SPI_Timer_Off();
|
||||
if(SPI_Timer_Status()==FALSE) ct = 0;
|
||||
if(__SD_Send_Cmd(CMD59, 0)) ct = 0; // Deactivate CRC check (default)
|
||||
if(__SD_Send_Cmd(CMD16, 512)) ct = 0; // Set R/W block length to 512 bytes
|
||||
// CCS in the OCR?
|
||||
if ((SPI_Timer_Status()==TRUE)&&(__SD_Send_Cmd(CMD58, 0) == 0))
|
||||
{
|
||||
SPI_R(ocr, 4);
|
||||
// SD version 2?
|
||||
ct = (ocr[0] & 0x40) ? SDCT_SD2 | SDCT_BLOCK : SDCT_SD2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// SD version 1 or MMC?
|
||||
if (__SD_Send_Cmd(ACMD41, 0) <= 1)
|
||||
{
|
||||
// SD version 1
|
||||
ct = SDCT_SD1;
|
||||
cmd = ACMD41;
|
||||
} else {
|
||||
// MMC version 3
|
||||
ct = SDCT_MMC;
|
||||
cmd = CMD1;
|
||||
}
|
||||
// Wait for leaving idle state
|
||||
SPI_Timer_On(250);
|
||||
while((SPI_Timer_Status()==TRUE)&&(__SD_Send_Cmd(cmd, 0)));
|
||||
SPI_Timer_Off();
|
||||
if(SPI_Timer_Status()==FALSE) ct = 0;
|
||||
if(__SD_Send_Cmd(CMD59, 0)) ct = 0; // Deactivate CRC check (default)
|
||||
if(__SD_Send_Cmd(CMD16, 512)) ct = 0; // Set R/W block length to 512 bytes
|
||||
}
|
||||
}
|
||||
if(ct) {
|
||||
dev->cardtype = ct;
|
||||
dev->mount = TRUE;
|
||||
dev->last_sector = __SD_Sectors(dev) - 1;
|
||||
printf("lastsec %u\n", dev->last_sector);
|
||||
#ifdef SD_IO_DBG_COUNT
|
||||
dev->debug.read = 0;
|
||||
dev->debug.write = 0;
|
||||
@@ -365,11 +377,14 @@ SDRESULTS SD_Read(SD_DEV *dev, void *dat, DWORD sector, WORD ofs, WORD cnt)
|
||||
WORD remaining;
|
||||
res = SD_ERROR;
|
||||
if ((sector > dev->last_sector)||(cnt == 0)) return(SD_PARERR);
|
||||
// Convert sector number to byte address (sector * SD_BLK_SIZE)
|
||||
if (__SD_Send_Cmd(CMD17, sector * SD_BLK_SIZE) == 0) {
|
||||
// Convert sector number to byte address (sector * SD_BLK_SIZE) for SDC1
|
||||
if (!(dev->cardtype & SDCT_BLOCK))
|
||||
sector *= SD_BLK_SIZE;
|
||||
|
||||
if (__SD_Send_Cmd(CMD17, sector) == 0) {
|
||||
SPI_Timer_On(100); // Wait for data packet (timeout of 100ms)
|
||||
do {
|
||||
tkn = SPI_RW(0xFF);
|
||||
SPI_R(&tkn, 1);
|
||||
} while((tkn==0xFF)&&(SPI_Timer_Status()==TRUE));
|
||||
SPI_Timer_Off();
|
||||
// Token of single block?
|
||||
@@ -377,20 +392,14 @@ SDRESULTS SD_Read(SD_DEV *dev, void *dat, DWORD sector, WORD ofs, WORD cnt)
|
||||
// Size block (512 bytes) + CRC (2 bytes) - offset - bytes to count
|
||||
remaining = SD_BLK_SIZE + 2 - ofs - cnt;
|
||||
// Skip offset
|
||||
if(ofs) {
|
||||
do {
|
||||
SPI_RW(0xFF);
|
||||
} while(--ofs);
|
||||
if(ofs) {
|
||||
SPI_R(NULL, ofs);
|
||||
}
|
||||
// I receive the data and I write in user's buffer
|
||||
do {
|
||||
*(BYTE*)dat = SPI_RW(0xFF);
|
||||
dat++;
|
||||
} while(--cnt);
|
||||
SPI_R((BYTE*)dat, cnt);
|
||||
// Skip remaining
|
||||
do {
|
||||
SPI_RW(0xFF);
|
||||
} while (--remaining);
|
||||
// TODO: CRC
|
||||
SPI_R(NULL, remaining);
|
||||
res = SD_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@ typedef struct _SD_DEV {
|
||||
|
||||
#else // For use with uControllers
|
||||
|
||||
#include "sysconfig.h"
|
||||
#include "stddef.h"
|
||||
#include "spi_io.h" /* Provide the low-level functions */
|
||||
|
||||
/* Definitions of SD commands */
|
||||
|
||||
@@ -1,16 +1,35 @@
|
||||
#include <alt_types.h>
|
||||
#include <altera_avalon_spi.h>
|
||||
#include <altera_avalon_spi_regs.h>
|
||||
#include <altera_avalon_pio_regs.h>
|
||||
#include <sys/alt_timestamp.h>
|
||||
#include <system.h>
|
||||
#include <io.h>
|
||||
#include "i2c_opencores.h"
|
||||
#include "spi_io.h"
|
||||
#include "av_controller.h"
|
||||
|
||||
#define SD_SLAVE_ID 0
|
||||
extern alt_u8 sys_ctrl;
|
||||
|
||||
alt_u32 sd_timer_ts;
|
||||
|
||||
void SPI_Init (void) {
|
||||
return;
|
||||
I2C_init(SD_SPI_BASE,ALT_CPU_FREQ,400000);
|
||||
}
|
||||
|
||||
void SPI_W(BYTE *wd, int len) {
|
||||
SPI_write(SD_SPI_BASE, wd, len);
|
||||
}
|
||||
|
||||
void SPI_R(BYTE *rd, int len) {
|
||||
SPI_read(SD_SPI_BASE, rd, len);
|
||||
}
|
||||
|
||||
BYTE SPI_RW (BYTE d) {
|
||||
BYTE rdata;
|
||||
BYTE w;
|
||||
SPI_R(&w, 1);
|
||||
|
||||
alt_avalon_spi_command(SPI_0_BASE, SD_SLAVE_ID, 1, &d, 1, &rdata, 0);
|
||||
return rdata;
|
||||
return w;
|
||||
}
|
||||
|
||||
void SPI_Release (void) {
|
||||
@@ -18,29 +37,32 @@ void SPI_Release (void) {
|
||||
}
|
||||
|
||||
inline void SPI_CS_Low (void) {
|
||||
return;
|
||||
sys_ctrl &= ~SD_SPI_SS_N;
|
||||
IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, sys_ctrl);
|
||||
}
|
||||
|
||||
inline void SPI_CS_High (void){
|
||||
return;
|
||||
sys_ctrl |= SD_SPI_SS_N;
|
||||
IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, sys_ctrl);
|
||||
}
|
||||
|
||||
inline void SPI_Freq_High (void) {
|
||||
return;
|
||||
I2C_init(SD_SPI_BASE,ALT_CPU_FREQ,ALT_CPU_FREQ/SCL_MIN_CLKDIV);
|
||||
}
|
||||
|
||||
inline void SPI_Freq_Low (void) {
|
||||
return;
|
||||
I2C_init(SD_SPI_BASE,ALT_CPU_FREQ,400000);
|
||||
}
|
||||
|
||||
void SPI_Timer_On (WORD ms) {
|
||||
|
||||
sd_timer_ts = ms*(ALT_CPU_FREQ/1000);
|
||||
alt_timestamp_start();
|
||||
}
|
||||
|
||||
inline BOOL SPI_Timer_Status (void) {
|
||||
|
||||
return alt_timestamp() < sd_timer_ts;
|
||||
}
|
||||
|
||||
inline void SPI_Timer_Off (void) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef _SPI_IO_H_
|
||||
#define _SPI_IO_H_
|
||||
|
||||
#include "sysconfig.h"
|
||||
#include "integer.h" /* Type redefinition for portability */
|
||||
|
||||
|
||||
@@ -20,6 +21,20 @@
|
||||
*/
|
||||
void SPI_Init (void);
|
||||
|
||||
/**
|
||||
\brief Read sequence of bytes
|
||||
\param *rd Pointer to array where read bytes are written.
|
||||
\param len Length of the array.
|
||||
*/
|
||||
void SPI_R (BYTE *rd, int len);
|
||||
|
||||
/**
|
||||
\brief Write sequence of bytes
|
||||
\param *wd Pointer to array which holds the bytes.
|
||||
\param len Length of the array.
|
||||
*/
|
||||
void SPI_W (BYTE *wd, int len);
|
||||
|
||||
/**
|
||||
\brief Read/Write a single byte.
|
||||
\param d Byte to send.
|
||||
|
||||
Reference in New Issue
Block a user