Перейти к содержанию
    

Коллеги, добрый день.

 

Пытаюсь подключить microSD карту к интерфейсу SDIO STM32L151RDT

Возникла проблема с чтением.

 

Инициализация проходит.

На CMD2 , CMD3 карта отвечает.

Посылаю CMD7, получаю ответ с верным CRC

Посылаю CMD17 , получаю ответ с верным CRC

Перевожу SDIO в режим чтения. Он выдаёт ~40 клоков , после чего выставляет бит ошибки "не получен старт бит" .

 

Вопрос 1: правильно ли я понимаю, что "старт бит" должен быть выдан картой одновременной по всем линиям D0-D3 ?

 

Вопрос 2: Вижу по осциллографу, что на линии D0 во время пачки клоков что-то есть, на остальных высокий уровень(они все подтянуты к питанию) .

Можно ли предположить, что карта в SPI режиме ?

 

Вопрос 3 : Если карта на самом деле в SPI режиме, то как она должна попасть в SDIO режим ? Если это происходит путём подачи CMD0 в то время как линия DAT3/CS в высоком уровне, то это условие у меня выполняется, т.к. линии D0-D3 подтянуты к питанию.

 

Вопрос 4 : Правильно ли я понимаю алгоритм чтения в режиме SDIO ? Проинициализировались - > CMD7 c верным RCA -> CMD17 с одресом -> и карта начинает выдавать данные.

Не совсем понятно, надо ли в ответах на CMD7 CMD17 проверять ещё что-то, помимо того что они просто получены ? "карта начинает выдавать данные" - в ответ на клоки SDIO контроллера ? И перед данными выдаёт старт-бит ?

 

Заранее спасибо !

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И ещё, ни как не могу понять, что именно делает CMD7 . В документации написано "SELECT / DESELECT CARD". Ну а как понять, выбрана оказалась карта после очередной CMD7 , или наоборот ? Отпарвляю CMD7 , получаю ответ. Все последующие отправки-ответа нет.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Разобрался. Выкладываю свой максимально простой код. Надеюсь что кому-нибудь поможет. Кое-где есть функции операционной системы, ожидающие прерывания от выставления флагов в регистре состояния SDIO. Их легко заменить простой проверка этого регистра в бесконечном цикле, прерывание при этом надо отключить.

 

Ноги процессора настраиваются так. Принципиально, что на всех подтяжка к +

////////////////////

void SD_INTERFACE_INIT(void)

{

//включаем тактирование порта

RCC->AHBENR |= RCC_AHBENR_GPIOCEN;

RCC->AHBLPENR|=RCC_AHBLPENR_GPIOCLPEN;

 

RCC->AHBENR |= RCC_AHBENR_GPIODEN;

RCC->AHBLPENR|=RCC_AHBLPENR_GPIODLPEN;

 

__dsb(15);

 

//скорость порта максимальная

GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8|GPIO_OSPEEDER_OSPEEDR9|GPIO_OSPEEDER_OSPEEDR10|GPIO_OSPEE

DER_OSPEEDR11| GPIO_OSPEEDER_OSPEEDR12;

GPIOD->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR2;

 

//SD1 SDIO

GPIOC->MODER &= ~GPIO_MODER_MODER8;

GPIOC->MODER |= GPIO_MODER_MODER8_1;

GPIOC->MODER &= ~GPIO_MODER_MODER9;

GPIOC->MODER |= GPIO_MODER_MODER9_1;

GPIOC->MODER &= ~GPIO_MODER_MODER10;

GPIOC->MODER |= GPIO_MODER_MODER10_1;

GPIOC->MODER &= ~GPIO_MODER_MODER11;

GPIOC->MODER |= GPIO_MODER_MODER11_1;

GPIOC->MODER &= ~GPIO_MODER_MODER12;

GPIOC->MODER |= GPIO_MODER_MODER12_1;

 

GPIOD->MODER &= ~GPIO_MODER_MODER2;

GPIOD->MODER |= GPIO_MODER_MODER2_1;

 

GPIOC->PUPDR &=~ GPIO_PUPDR_PUPDR8;

GPIOC->PUPDR |= GPIO_PUPDR_PUPDR8_0;

GPIOC->PUPDR &=~ GPIO_PUPDR_PUPDR9;

GPIOC->PUPDR |= GPIO_PUPDR_PUPDR9_0;

GPIOC->PUPDR &=~ GPIO_PUPDR_PUPDR10;

GPIOC->PUPDR |= GPIO_PUPDR_PUPDR10_0;

GPIOC->PUPDR &=~ GPIO_PUPDR_PUPDR11;

GPIOC->PUPDR |= GPIO_PUPDR_PUPDR11_0;

GPIOC->PUPDR &=~ GPIO_PUPDR_PUPDR12;

GPIOC->PUPDR |= GPIO_PUPDR_PUPDR12_0;

 

GPIOD->PUPDR &=~ GPIO_PUPDR_PUPDR2;

GPIOD->PUPDR |= GPIO_PUPDR_PUPDR2_0;

 

GPIOC->AFR[1]|=(12<<0);

GPIOC->AFR[1]|=(12<<4);

GPIOC->AFR[1]|=(12<<8);

GPIOC->AFR[1]|=(12<<12);

GPIOC->AFR[1]|=(12<<16);

 

GPIOD->AFR[0]|=(12<<8);

}

 

SDIO настраивается так. Включены прерывания по всем важным флагам по итогам передачи команды и данных.

PLL настроен так, что частота процессора 32МГц, промежуточная частота PLL, от которой тактируется SDIO, 48МГц

 

//////////////////////////настраиваем SDIO для SD ///////////////////////////////////////////////////////

void SD_SDIO_INIT(void)

{

RCC->APB2ENR|=RCC_APB2ENR_SDIOEN; // включаем тактирование

RCC->APB2LPENR|=RCC_APB2LPENR_SDIOLPEN;

 

RCC->APB2RSTR|=RCC_APB2RSTR_SDIORST;

RCC->APB2RSTR&=~RCC_APB2RSTR_SDIORST; //сброс настроек

 

SDIO->CLKCR|=SDIO_CLKCR_HWFC_EN; //HW Flow Control is enabled

SDIO->CLKCR|=SDIO_CLKCR_WIDBUS_0; // 4-wide bus mode: SDIO_D[3:0] used ++

SDIO->CLKCR|=SDIO_CLKCR_PWRSAV; //SDIO_CK is only enabled when the bus is active

SDIO->CLKCR|=SDIO_CLKCR_CLKEN; //SDIO_CK is enabled ++

 

 

SDIO->DCTRL|=SDIO_DCTRL_SDIOEN;

SDIO->DCTRL|=SDIO_DCTRL_RWMOD; //Read Wait control using SDIO_CK ///Непонятно, что это

SDIO->DCTRL|=SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DBLOCKSIZE_3; // размер блока 512 ++

SDIO->DCTRL|=SDIO_DCTRL_DMAEN; //DMA enabled. ++

 

///////включаем прерывания

SDIO->MASK|=SDIO_MASK_STBITERRIE;

SDIO->MASK|=SDIO_MASK_DATAENDIE;

SDIO->MASK|=SDIO_MASK_CMDRENDIE;

SDIO->MASK|=SDIO_MASK_DTIMEOUTIE;

SDIO->MASK|=SDIO_MASK_CTIMEOUTIE;

SDIO->MASK|=SDIO_MASK_DCRCFAILIE;

SDIO->MASK|=SDIO_MASK_CCRCFAILIE;

SDIO->MASK|=SDIO_MASK_CMDSENTIE;

 

NVIC_SetPriority(SDIO_IRQn, 11);

NVIC_EnableIRQ(SDIO_IRQn);

 

SDIO->POWER|=SDIO_POWER_PWRCTRL ; //Включаем SDIO

 

}

 

функция передачи CMD команды. После начала передачи функция ждёт прерывания от выставления флагов в SDIO STA . У меня операционка, но её можно выкинуть, заменив просто поллингом регистра STA, или передачей флага из прерывания через глобальную переменную.

 

////////////////////////////////////////

__inline char SEND_CMD(char sd_n, unsigned char cmd, unsigned long int argument, unsigned char response_type, unsigned int* ansver )

{

unsigned int SDIO_CMD_MASK;

EventBits_t SDIO_STA_MASK;

 

//Clear the Command Flags

SDIO->ICR=0xFFFFFFFF; //(SDIO_STA_CCRCFAIL | SDIO_STA_CTIMEOUT | SDIO_STA_CMDREND | SDIO_STA_CMDSENT);

SDIO->ARG=argument; //First adjust the argument (because I will immediately enable CPSM next)

SDIO_CMD_MASK=cmd; //The last argument is to enable CSPM

SDIO_CMD_MASK |=SDIO_CMD_CPSMEN; //The last argument is to enable CSPM

switch(response_type){

case RESPONSE_0_BIT :

SDIO_CMD_MASK &=~SDIO_CMD_WAITRESP_0;

SDIO_CMD_MASK &=~SDIO_CMD_WAITRESP_1;

break;

case RESPONSE_48_BIT :

SDIO_CMD_MASK |=SDIO_CMD_WAITRESP_0;

SDIO_CMD_MASK &=~SDIO_CMD_WAITRESP_1;

break;

case RESPONSE_136_BIT :

SDIO_CMD_MASK |=SDIO_CMD_WAITRESP_0;

SDIO_CMD_MASK |=SDIO_CMD_WAITRESP_1;

default :

SDIO_CMD_MASK |=SDIO_CMD_WAITRESP_0;

SDIO_CMD_MASK |=SDIO_CMD_WAITRESP_1;

}

 

xEventGroupClearBits(x_SDIO_Transmit_EventGroup,0xFFFFFFF);

SDIO->CMD=SDIO_CMD_MASK; //запускаем передачу команды

 

if (response_type==RESPONSE_0_BIT)

{

SDIO_STA_MASK=xEventGroupWaitBits(x_SDIO_Transmit_EventGroup, SDIO_STA_CMDSENT | SDIO_STA_CTIMEOUT, pdTRUE, pdFALSE, 5);

if(SDIO_STA_MASK & SDIO_STA_CTIMEOUT)

return SD_ERROR;

return SD_OK;

}

else //SHRESP or LNRESP or R3RESP

{

SDIO_STA_MASK=xEventGroupWaitBits(x_SDIO_Transmit_EventGroup, SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL, pdTRUE, pdFALSE, 5);

 

if(SDIO_STA_MASK & SDIO_STA_CTIMEOUT)

return SD_ERROR;

if(SDIO_STA_MASK& SDIO_STA_CCRCFAIL)

{

if(cmd==CMD41)

{

ansver[0]=SDIO->RESP1;

ansver[1]=SDIO->RESP2;

return SD_OK;

}

else

return SD_ERROR;

}

if(SDIO_STA_MASK & SDIO_STA_CMDREND)

{

ansver[0]=SDIO->RESP1;

ansver[1]=SDIO->RESP2;

if(response_type==RESPONSE_136_BIT)

{

ansver[2]=SDIO->RESP3;

ansver[3]=SDIO->RESP4;

}

return SD_OK;

}

}

return SD_ERROR;

}

 

 

Функция настройки DMA для передачи SDIO <> буфер памяти

///////////////////////////////////////////////////////////////////////////////////

void SD_DMA_INIT(void)

{

RCC->AHBENR|=RCC_AHBENR_DMA2EN; //включили тактирование DMA

RCC->AHBLPENR|=RCC_AHBLPENR_DMA2LPEN;

 

RCC->AHBRSTR&=~RCC_AHBRSTR_DMA2RST;//перестаём сбрасывать настройки DMA

 

//передача и приём

DMA2_Channel4->CCR&=~DMA_CCR4_EN;// выключили канал

DMA2_Channel4->CCR|=DMA_CCR4_TCIE;// прерывание при конце передачи

DMA2_Channel4->CCR|=DMA_CCR4_MSIZE_1; //размер памяти 32

DMA2_Channel4->CCR|=DMA_CCR4_PSIZE_1; //размер периферии 32

}

}

 

Функции запуска DMA для чтения и для записи

///////////////////////////////запускаем чтение SD по DMA /////////////////////////////////

void SD_DMA_START_READ(char sd_n, unsigned char *p_buf_r, int data_size)

{

// "периферия" -откуда берутся данные

// "память" -куда идёт данные

if(sd_n==SD1)

{

DMA2_Channel4->CCR&=~DMA_CCR4_EN; // канал приёма и передачи

 

DMA2_Channel4->CNDTR=data_size/4; //т.к. data_size в байтах, а размер регистра 32 байта

DMA2_Channel4->CMAR=(uint32_t)p_buf_r; // сюда идут данные

DMA2_Channel4->CPAR=(uint32_t)(&SDIO->FIFO); // отсюда идут данные

DMA2_Channel4->CCR|=DMA_CCR4_MINC;

DMA2_Channel4->CCR &=~ DMA_CCR4_PINC;

 

 

DMA2_Channel4->CCR|=DMA_CCR4_EN;

 

}

 

}

 

///////////////////////////////запускаем запись в SD по DMA /////////////////////////////////

void SD_DMA_START_WRITE(char sd_n, unsigned char *p_buf_w, int data_size)

{

// "периферия" -откуда берутся данные

// "память" -куда идёт данные

 

DMA2_Channel4->CCR&=~DMA_CCR4_EN; // канал приёма и передачи

 

DMA2_Channel4->CNDTR=data_size/4; //т.к. data_size в байтах, а размер регистра 32 байта

DMA2_Channel4->CPAR=(uint32_t)p_buf_w; // сюда идут данные

DMA2_Channel4->CMAR=(uint32_t)(&SDIO->FIFO); // отсюда идут данные

DMA2_Channel4->CCR|=DMA_CCR4_PINC;

DMA2_Channel4->CCR&=~DMA_CCR4_MINC;

 

DMA2_Channel4->CCR|=DMA_CCR4_EN;

}

 

Инициализация карты. Работает только на картах больше 2Гб. См. комментарии.

///// Как это работает написано в документе Part_1_Physical_Layer_Simplified_Specification_Ver3.01_Final_100518-1.pdf страница 115

char SD_initialize (char sd_n)

{

unsigned int cmd_ansver[4];

char result;

unsigned long int time;

unsigned int C_SIZE;

 

time=xTaskGetTickCount()+(2000/portTICK_RATE_MS);

 

SD_SCK_DIV_60(sd_n)

 

SEND_CMD(sd_n, CMD0,0,RESPONSE_0_BIT,&cmd_ansver[0]);

SEND_CMD(sd_n, CMD0,0,RESPONSE_0_BIT,&cmd_ansver[0]); //почему то c одним CMD0 не работает

result=SEND_CMD(sd_n, CMD8,0x1AA,RESPONSE_48_BIT,&cmd_ansver[0]);

if(result==SD_OK) //карта ответила на CMD8

{

if((cmd_ansver[0] & 0x1FF)!=0x1AA) //контрольная цифра не верна

{

result= FR_DISK_ERR;

}

else

{

while(1)

{

result=SEND_CMD(sd_n, CMD55,0,RESPONSE_48_BIT,&cmd_ansver[0]);

if(result==SD_OK)

result=SEND_CMD(sd_n, CMD41, /*(1<<31)*/ 0x80000000 |(1<<20)|(1<<30)|(1<<28) ,RESPONSE_48_BIT,&cmd_ansver[0]); //|(1<<28) включает макс.скорость

if(result==SD_OK)

{

if((cmd_ansver[0] & /*(1<<31)*/ 0x80000000)!=0) //инициализация пройдена

{

if((cmd_ansver[0] & (1<<30))!=0) //CCS=1

CardType[sd_n]=SDHC_SDXC;

else //CCS=0

CardType[sd_n]=SDSC;

 

result=SEND_CMD(sd_n, CMD2,0,RESPONSE_136_BIT,&cmd_ansver[0]);

if(result==SD_OK)

result=SEND_CMD(sd_n, CMD3,0,RESPONSE_48_BIT,&cmd_ansver[0]);

if(result==SD_OK)

sd_RCA[sd_n]=(cmd_ansver[0])>>16;

break;

}

}

else

{

result= FR_DISK_ERR;

break;

}

 

if(xTaskGetTickCount()>time)

{

result= FR_DISK_ERR;

break;

}

}

}

}

else //карта не ответила на CMD8

{

while(1)

{

result=SEND_CMD(sd_n, CMD55,0,RESPONSE_48_BIT,&cmd_ansver[0]);

if(result==SD_OK)

result=SEND_CMD(sd_n, CMD41, /*(1<<31)*/ 0x80000000 |(1<<20)|(1<<28) ,RESPONSE_48_BIT,&cmd_ansver[0]);

if(result==SD_OK)

{

if((cmd_ansver[0] & /*(1<<31)*/ 0x80000000)!=0) //инициализация пройдена

{

CardType[sd_n]=SDSC;

result =FR_OK;

break;

}

}

else

{

result= FR_DISK_ERR;

break;

}

 

if(xTaskGetTickCount()>time)

{

result= FR_DISK_ERR;

break;

}

}

}

 

//Включаем частоту шины в соответствии с классом скорости карты. Надо бы сделать получение класса скорости от карты.

SD_SCK_DIV_8(sd_n)

 

//Узнаём количество секторов на карте

if(result==SD_OK)

result=SEND_CMD(sd_n, CMD9, sd_RCA[sd_n]<<16, RESPONSE_136_BIT, &cmd_ansver[0]);

if(CardType[sd_n]==SDHC_SDXC)

{

C_SIZE =((cmd_ansver[1] & 0x1F)<<17) + ((cmd_ansver[2] & 0xFFFF0000)>>16); //биты 69-48

sd_total_sectors[sd_n]=C_SIZE*1024;

}

else

{

sd_total_sectors[sd_n]=0; //тут надо бы сделать обработку старых карт

}

 

if(result==SD_OK)

result=SEND_CMD(sd_n, CMD7, sd_RCA[sd_n]<<16, RESPONSE_48_BIT, &cmd_ansver[0]);

if(result==SD_OK)

result=SEND_CMD(sd_n, CMD55, sd_RCA[sd_n]<<16 , RESPONSE_48_BIT, &cmd_ansver[0]);

if(result==SD_OK)

result=SEND_CMD(sd_n, CMD6, 0x02, RESPONSE_48_BIT, &cmd_ansver[0]); //выбираем шину 4 бита

 

 

return result;

}

 

Функция чтения

/////////////////////////////////////////////////////////////////////

__inline DRESULT TRY_disk_read (

BYTE Drive, /* Physical drive number */

BYTE* pBuffer, /* Pointer to the read data buffer */

DWORD SectorNumber, /* Start sector number */

BYTE SectorCount /* Number of sectros to read */

)

{

unsigned long int sd_adress,number_of_block;

unsigned long int i;

unsigned char result;

char sd_n =Drive;

EventBits_t SDIO_STA_MASK;

 

unsigned int cmd_ansver[4];

 

if(CardType[sd_n]==SDHC_SDXC)

sd_adress=SectorNumber;

else

sd_adress=SectorNumber*0x200;

 

number_of_block=SectorCount;

 

for(i=0;i<number_of_block;i++)

{

result=SEND_CMD(sd_n, CMD17, sd_adress+(i*512), RESPONSE_48_BIT, &cmd_ansver[0]);

if(result!=SD_OK)

{

ADD_EVENT_MESSAGE_SDx(sd_n,"#!!! ERROR: TRY_disk_read: CMD18: Ошибка 2#");

return RES_ERROR;

}

 

//xSemaphoreTake(x_SD_Multi_Transmit_Complite[sd_n],0);//

xEventGroupClearBits(x_SDIO_Transmit_EventGroup,0xFFFFFFF);

SD_DMA_START_READ(sd_n,pBuffer+(i*512),512);

 

SDIO->ICR=0xFFFFFFFF;

 

SDIO->DTIMER= 0xffffff;

SDIO->DLEN=512;

 

SDIO->DCTRL=SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DBLOCKSIZE_3; // размер блока 512

SDIO->DCTRL|=SDIO_DCTRL_DMAEN; //DMA enabled.

SDIO->DCTRL|=SDIO_DCTRL_DTDIR; //Direction. //направление передачи из дарты в процессор

SDIO->DCTRL|=SDIO_DCTRL_RWSTART; //

SDIO->DCTRL|=SDIO_DCTRL_DTEN; //DPSM is enabled //запускаем передачу данных

 

//Ждём выставления флагов в прерывании. По результатам судим о успехе/не успехе передачи

SDIO_STA_MASK=xEventGroupWaitBits(x_SDIO_Transmit_EventGroup, SDIO_STA_DBCKEND | SDIO_STA_STBITERR /*| SDIO_STA_DATAEND */ | SDIO_STA_DTIMEOUT | SDIO_STA_DCRCFAIL, pdTRUE, pdFALSE, 10);

if(SDIO_STA_MASK & SDIO_STA_CTIMEOUT)

return RES_ERROR;

 

if(SDIO_STA_MASK & (SDIO_STA_STBITERR | SDIO_STA_DTIMEOUT | SDIO_STA_DCRCFAIL ))

return RES_ERROR;

}

return RES_OK;

}

 

И очень похожая функция записи

/////////////////////////////////////////////////////////////////////

__inline DRESULT TRY_disk_write(

BYTE Drive, /* Physical drive number */

unsigned char* pBuffer, /* Pointer to the read data buffer */

DWORD SectorNumber, /* Start sector number */

BYTE SectorCount /* Number of sectros to read */

 

)

{

char sd_n=Drive;

char result;

unsigned long int i;

unsigned long int sd_adress,number_of_block;

EventBits_t SDIO_STA_MASK;

 

unsigned int cmd_ansver[4];

 

if(CardType[sd_n]==SDHC_SDXC)

sd_adress=SectorNumber;

else

sd_adress=SectorNumber*0x200;

 

number_of_block=SectorCount;

 

for(i=0;i<number_of_block;i++)

{

result=SEND_CMD(sd_n, CMD24, sd_adress+(i*512), RESPONSE_48_BIT, &cmd_ansver[0]);

if(result!=SD_OK)

{

ADD_EVENT_MESSAGE_SDx(sd_n,"#!!! ERROR: TRY_disk_write: CMD24: Ошибка 2#");

return RES_ERROR;

}

 

xEventGroupClearBits(x_SDIO_Transmit_EventGroup,0xFFFFFFF);

SD_DMA_START_WRITE(sd_n,pBuffer+(i*512),512);

 

SDIO->ICR=0xFFFFFFFF;

 

SDIO->DTIMER= 0xffffff;

SDIO->DLEN=512;

 

SDIO->DCTRL=SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DBLOCKSIZE_3; // размер блока 512

SDIO->DCTRL|=SDIO_DCTRL_DMAEN; //DMA enabled.

SDIO->DCTRL &=~ SDIO_DCTRL_DTDIR; //Direction. //направление передачи из процессора в карту

SDIO->DCTRL|=SDIO_DCTRL_DTEN; //DPSM is enabled //запускаем передачу

 

SDIO_STA_MASK=xEventGroupWaitBits(x_SDIO_Transmit_EventGroup, SDIO_STA_DBCKEND | SDIO_STA_STBITERR /*| SDIO_STA_DATAEND */ | SDIO_STA_DTIMEOUT | SDIO_STA_DCRCFAIL, pdTRUE, pdFALSE, 10);

if(SDIO_STA_MASK & SDIO_STA_CTIMEOUT)

return RES_ERROR;

 

if(SDIO_STA_MASK & (SDIO_STA_STBITERR | SDIO_STA_DTIMEOUT | SDIO_STA_DCRCFAIL ))

return RES_ERROR;

}

return RES_OK;

 

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Аминь:)

Кстати, у вас в SEND_CMD() не хватает break-а в ветке case RESPONSE_136_BIT. Просто глаз зацепился.

Ну и в тэги [сode]/[сodebox] бы код оформить...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну и в тэги [сode]/[сodebox] бы код оформить...

 

Сколько раз пробовал, у меня код в этих тегах разъезжается. Перед каждой строчкой появляется непредсказуемое количество пробелов, причём редактировать их количество так что бы становилось ровно не получается.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Подскажите, какой командой в режиме SDIO узнают, готова ли карта для приёма следующего блока данных ? При записи нескольких блоков подряд происходит ошибка, а если вставить задержки то всё хорошо.

И то же самое при мультиблочной записи(CMD25) . На втором блоке SDIO выставляет флаг ошибки STA DCRCFAIL . А если блоки разделить задержками, то всё хорошо. Что на самом деле нужно делать между отправками блоков в мультиблочной записи ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Перед отправкой команд CMD24/CMD25 нужно дожидаться готовности карты.

Для этого читать статус (CMD13_SEND_STATUS), и проверять бит READY_FOR_DATA.

После этого можно писать. (Между блоками в мультиблочной записи проверять готовность не нужно. По крайней мере, если пишем через DMA).

Точно так же нужно проверять готовность перед командами чтения (CMD17/CMD18).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Перед отправкой команд CMD24/CMD25 нужно дожидаться готовности карты.

Для этого читать статус (CMD13_SEND_STATUS), и проверять бит READY_FOR_DATA.

После этого можно писать. (Между блоками в мультиблочной записи проверять готовность не нужно. По крайней мере, если пишем через DMA).

Точно так же нужно проверять готовность перед командами чтения (CMD17/CMD18).

 

Спасибо.

У меня проблема исчезла, после того как вставил CMD13 с проверкой бита READY_FOR_DATA между блоками в мультиблочной передаче(CMD25). Перед CMD25 проверка READY_FOR_DATA не помогла.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Перед отправкой команд CMD24/CMD25 нужно дожидаться готовности карты.

Для этого читать статус (CMD13_SEND_STATUS), и проверять бит READY_FOR_DATA.

После этого можно писать. (Между блоками в мультиблочной записи проверять готовность не нужно. По крайней мере, если пишем через DMA).

Точно так же нужно проверять готовность перед командами чтения (CMD17/CMD18).

 

Спасибо.

У меня проблема исчезла, после того как вставил CMD13 с проверкой бита READY_FOR_DATA между блоками в мультиблочной передаче(CMD25). Перед CMD25 проверка READY_FOR_DATA не помогла.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я что-то не понял. Вы что, блоки отправляете по одному? Так ведь вся суть команды CMD25 в том, что можно отправить сразу много блоков одной пачкой!

Допустим, у вас 4К данных. Вы ждёте готовности (CMD13), потом даёте команду CMD25, и натравливаете DMA на все свои 4К. И все 4К сразу и передаются.

Где здесь "между блоками"?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Где здесь "между блоками"?

 

Почему-то я был уверен, что блоки можно отправлять только по одному, и после каждого надо ждать выставления флагов в SDIO STA . Сейчас попробовал все разом, и действительно, заработало !

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нет ли у кого-нибудь информации о том, в каких типах карт допустима невыравненная мультиблоковая запись? На некоторых SDHC я проверял - работает. Пока неработающую не встретил. А т.к. винда злостно форматирует кластеры на невыравненных адресах, то разбивать 4К кластер на 4+2+1+1 сектор записи вместо одной в 8 секторов - это непозволительная роскошь. Насколько я заметил, стыковка даже мультиблоков делается самой картой (SDHC) и только в момент ухода с какой-то внутренней грануляции карты возникает процесс записи и выдача BUSY. Вопрос насколько старые карты так умеют делать? MMC? SD ver1?

 

... Между блоками в мультиблочной записи проверять готовность не нужно. ...

При невыравненном доступе - нужно. Прямо между блоками может 50 мс BUSY встрять.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нет ли у кого-нибудь информации о том, в каких типах карт допустима невыравненная мультиблоковая запись?

 

Не совсем понятно, что значит "невыровненная". Речь идёт о выравнивании адреса на 0x200 байт , или о чём-то ещё ?

И , ради любопытства, зачем Вам это ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нееее. У SDHC передаётся сразу номер блока/сектора (т.н. сектор = 512 байт блок).

 

А невыровненная это когда по адресу блока допустим 0x0015 пишется блок длиной 0x003F блоков. Здесь уже и адрес и длина блока невыровненные. Но длина блока некратная степени двойки это я ещё не проверял. Но , думаю, на SDHC вполне может работать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

по адресу блока допустим 0x0015 пишется блок длиной 0x003F блоков. Здесь уже и адрес и длина блока невыровненные.

 

Я давно и много работаю с самыми разными SD , но Ваших слов почему-то не понимаю.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...