|
microSD SDIO, Помогите начать |
|
|
|
Oct 30 2014, 17:11
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Коллеги, добрый день.
Пытаюсь подключить 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 контроллера ? И перед данными выдаёт старт-бит ?
Заранее спасибо !
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
 |
Ответов
(1 - 49)
|
Nov 1 2014, 17:34
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Разобрался. Выкладываю свой максимально простой код. Надеюсь что кому-нибудь поможет. Кое-где есть функции операционной системы, ожидающие прерывания от выставления флагов в регистре состояния 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; }
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Mar 30 2015, 20:09
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(AHTOXA @ Mar 30 2015, 22:35)  Насколько я понял, первый роялит только для не-SDHC карт. (Потому что для SDHC карт не получится передать невыровненный адрес). Да, в HC это убрали, но и на обычных картах никто (или почти никто) такую запись не поддерживал. Цитата(AHTOXA @ Mar 30 2015, 22:35)  Что же до флага BUSY при мультиблоковой записи - не разу его не проверял, и не имел проблем. Возможно, с ним работает аппаратура SDIO контроллера. BUSY, естественно, выставляется - иначе у карты не было бы возможности "притормозить" запись.
|
|
|
|
|
Jul 19 2015, 18:02
|

Частый гость
 
Группа: Участник
Сообщений: 116
Регистрация: 27-01-10
Из: СПб
Пользователь №: 55 094

|
Пытаю SDIO на плате SK-STM32F217. Карту пока не подключал, хочу увидеть хоть какую-нибудь осмысленную активность на сигнальных линиях. Осуществляю инициализацию и отправку команды, но вижу только мусор на линии CLK, на остальных ничего нет. Может кто-нибудь проверить у себя мой вариант? Или подкинуть 100% рабочий код, без лишних функций. Код static SDIO_InitTypeDef s_sdio_param = { SDIO_ClockEdge_Rising, SDIO_ClockBypass_Enable, SDIO_ClockPowerSave_Disable, SDIO_BusWide_1b, SDIO_HardwareFlowControl_Disable, 0 };
void bsp_sd_init (void) { SDIO_CmdInitTypeDef SDIO_CmdInitStruct;
s_gpio_init();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);
SDIO_SetPowerState(SDIO_PowerState_ON); while (SDIO_GetPowerState() != 0x03) { continue; }
SDIO_Init(&s_sdio_param);
SDIO_ClockCmd(ENABLE);
SDIO_CmdInitStruct.SDIO_CmdIndex = 0xAA; SDIO_CmdInitStruct.SDIO_Argument = 0xCCCCCCCC; SDIO_CmdInitStruct.SDIO_Response = SDIO_Response_No; SDIO_CmdInitStruct.SDIO_CPSM = ENABLE; SDIO_CmdInitStruct.SDIO_Wait = SDIO_Wait_No; SDIO_SendCommand(&SDIO_CmdInitStruct); }
static void s_gpio_init (void) { GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_CLK | RCC_CMD | RCC_D3 | RCC_D2 | RCC_D1 | RCC_D0, ENABLE);
GPIO_PinAFConfig(GPIO_CLK, PINSOURCE_CLK, GPIO_AF_SDIO); GPIO_PinAFConfig(GPIO_CMD, PINSOURCE_CMD, GPIO_AF_SDIO); GPIO_PinAFConfig(GPIO_D3, PINSOURCE_D3, GPIO_AF_SDIO); GPIO_PinAFConfig(GPIO_D2, PINSOURCE_D2, GPIO_AF_SDIO); GPIO_PinAFConfig(GPIO_D1, PINSOURCE_D1, GPIO_AF_SDIO); GPIO_PinAFConfig(GPIO_D0, PINSOURCE_D0, GPIO_AF_SDIO);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = PIN_CMD; GPIO_Init(GPIO_CMD, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = PIN_D3; GPIO_Init(GPIO_D3, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = PIN_D2; GPIO_Init(GPIO_D2, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = PIN_D1; GPIO_Init(GPIO_D1, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = PIN_D0; GPIO_Init(GPIO_D0, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_Pin = PIN_CLK; GPIO_Init(GPIO_CLK, &GPIO_InitStructure); }
Сообщение отредактировал ohmjke - Jul 19 2015, 18:03
|
|
|
|
|
Jan 31 2018, 09:23
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(Мур @ Jan 31 2018, 11:24)  Это ценно. Огромное ВАМ спасибо!!!
...остается выяснить CRC вычисляется с учетом этого стартового нуля или ТОЛЬКО данные в учете? Рекомендую ознакомиться с SD Specifications Part 1 Physical Layer Simplified Specification Version 3.01: Цитата When the wide bus option is used, the data is transferred 4 bits at a time (refer to Figure 3-7). Start and end bits, as well as the CRC bits, are transmitted for every one of the DAT lines. CRC bits are calculated and checked for every DAT line individually. The CRC status response and Busy indication will be sent by the card to the host on DAT0 only (DAT1-DAT3 during that period are don't care). Более подробно про разные CRC описано в разделе 4.5 Cyclic Redundancy Code (CRC).
|
|
|
|
|
Feb 1 2018, 07:46
|

Знающий
   
Группа: Свой
Сообщений: 815
Регистрация: 7-06-06
Из: Харьков
Пользователь №: 17 847

|
Цитата(aaarrr @ Jan 31 2018, 23:11)  Что может быть проще, чем иметь четыре сдвиговых регистра на выходе сериализатора? Минимум манипуляций с данными, минимум логики. Смеётесь?.... В 4 раза больше логики в вашем случае! (16 триггеров против 64х). Есть только одно объяснение этому "безобразию",- вариант применения одной линии данных вместо четырех. Тогда берется для этого один регистр из четырех.
|
|
|
|
|
Feb 1 2018, 12:46
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(mantech @ Feb 1 2018, 13:55)  Если только скорость вообще не важна  А какой реальный выигрыш от использования SDIO вместо SPI не на коне в вакууме, а на типичном Cortex-M? Загруженном кроме гоняния байтов с SD ещё и другими задачами. В Мб/сек или в %. Есть-ли вообще смысл тратить гораздо больше ног МК, которые, как правило, всегда в дефиците?
|
|
|
|
|
Feb 1 2018, 13:03
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(jcxz @ Feb 1 2018, 15:46)  А какой реальный выигрыш от использования SDIO вместо SPI не на коне в вакууме Действительно, реальная карта очень медленная. Т.е. по быстрому интерфейсу ей прилетает команда, спустя какое-то время карта по быстрому интерфейсу отвечает, а данные сектора выдаст гораааздо позже, но очень быстро. Применение SDIO в связке с DMA позволяет сильно разгрузить МК, хотя я делал и на SPI+DMA+ISR с деревом из callback-функций. С учетом того, что карта может приспокойно "задуматься" на полсекунды даже в режиме чтения, jcxz весьма справедлив.
|
|
|
|
|
Feb 1 2018, 13:15
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(adnega @ Feb 1 2018, 15:03)  С учетом того, что карта может приспокойно "задуматься" на полсекунды даже в режиме чтения, jcxz весьма справедлив. Я даже не об этом говорю, а о том что на практике я писал драйвер SD через SPI на Cortex-M 120МГц. И получал скорость потокового чтения с карты немного больше 1МБ/сек (естественно SPI+DMA). Даже просто прокачка такого потока через средний Cortex-M сильно его нагрузит. Не говоря уже о том, что наверное МК должен как-то ещё и обрабатывать этот поток. При более-менее содержательной обработке читаемых/записываемых данных, скорость обработки этих данных вряд-ли будет выше 1МБ/сек, а скорей всего - гораздо ниже. Тогда такой скорости SPI вполне хватает. И это при том, что я даже не оптимизировал свой драйвер - возможно получил бы гораздо бОльшую скорость (SPI-флешки у меня работают на SCLK до 40МГц). Вобщем: при реальной работе с SD, а не мерянии попугаев, сама обработка данных будет больше тормозить, чем обмен с SD по SPI. Имха. Так что польза от SDIO на типичных Cortex-M - сомнительна. Тоже - имхо.
|
|
|
|
|
Feb 1 2018, 13:32
|

Профессионал
    
Группа: Свой
Сообщений: 1 262
Регистрация: 13-10-05
Из: Санкт-Петербург
Пользователь №: 9 565

|
Цитата(jcxz @ Feb 1 2018, 15:46)  А какой реальный выигрыш от использования SDIO вместо SPI не на коне в вакууме, а на типичном Cortex-M? Загруженном кроме гоняния байтов с SD ещё и другими задачами. В Мб/сек или в %. Есть-ли вообще смысл тратить гораздо больше ног МК, которые, как правило, всегда в дефиците? Есть проект на Cortex-M7 вида eMMC -> M7 -> HSUSB, без двойной буверизации, т.е. блок читается с флешки и отдаётся в USB. При подключении по 4 проводам SDIO средня скорость чтения файла длиной 1Гб, в зависимости от частоты шины SDIO, составила: 24.43МГц - 6.50М/с; 25.00МГц - 7.18М/с; 50.00МГц - 10.56М/с. Насколькоя я знаю скорость 50.00МГц предусмотрена стандартом только в режиме SDIO. Цитата(adnega @ Feb 1 2018, 16:03)  С учетом того, что карта может приспокойно "задуматься" на полсекунды даже в режиме чтения, jcxz весьма справедлив. Моя карта имеет право задуматься на 250мс в режиме чтения.
|
|
|
|
|
Feb 1 2018, 13:47
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(_4afc_ @ Feb 1 2018, 15:32)  Насколькоя я знаю скорость 50.00МГц предусмотрена стандартом только в режиме SDIO. Просто передаёт с SD на USB? Это карт-ридер? Конечно, если делать карт-ридер, то здесь имеет смысл. Я же писал про использование SD для нужд хранения и содержательной обработки данных самой программой МК. Единственный вариант: это если данные медленно накапливать на SD при работе устройства, а потом быстро слить в комп не вынимая карты. Цитата(_4afc_ @ Feb 1 2018, 15:32)  Моя карта имеет право задуматься на 250мс в режиме чтения. Да уж....
|
|
|
|
|
Feb 1 2018, 14:09
|

Профессионал
    
Группа: Свой
Сообщений: 1 262
Регистрация: 13-10-05
Из: Санкт-Петербург
Пользователь №: 9 565

|
Цитата(jcxz @ Feb 1 2018, 16:47)  Единственный вариант: это если данные медленно накапливать на SD при работе устройства, а потом быстро слить в комп не вынимая карты. Да что-то подобное. Цитата(jcxz @ Feb 1 2018, 16:47)  Просто передаёт с SD на USB? Это карт-ридер?  В режиме чтения накопленной или обработанной информации - что-то типа карт-ридера. И естественно, чем быстрее считается - тем удобнее. Цитата(jcxz @ Feb 1 2018, 16:47)  Конечно, если делать карт-ридер, то здесь имеет смысл. Я же писал про использование SD для нужд хранения и содержательной обработки данных самой программой МК. Для нужд записи - тоже имеет смысл при ограничении по потреблению и пульсациям по питанию. Вот ток потребления в режиме SPI:
А вот в режиме SDIO:
Видно, что среднее потребление при записи - в режиме SDIO в 2.5 раза меньше, за счёт меньшего времени передачи данных.
|
|
|
|
|
Feb 1 2018, 14:17
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(_4afc_ @ Feb 1 2018, 16:09)  Для нужд записи - тоже имеет смысл при ограничении по потреблению и пульсациям по питанию. ... Видно, что среднее потребление при записи - в режиме SDIO в 2.5 раза меньше, за счёт меньшего времени передачи данных. Зато судя по картинкам - пульсация тока в режиме SDIO в ~2 раза больше Да и судя по длительностям осциллограмм - сравниваете SDIO работающий на высокой скорости и SPI работающий на медленной скорости - так сравнивать не корректно. Вы сами писали, что скорость SDIO у вас максимум была 10МБ/сек. А SPI может работать с SCLK до 25МГц - т.е. около 3МБ/сек. Разница в длительности картинок должна быть соответственно 1/3 или 1/4 (судя по кол-ву линий IO). Возможно, что если запустите SPI на макс. скорости, то получите сравнимые показатели тока потребления.
|
|
|
|
|
Feb 2 2018, 07:49
|

Знающий
   
Группа: Свой
Сообщений: 815
Регистрация: 7-06-06
Из: Харьков
Пользователь №: 17 847

|
Цитата(aaarrr @ Jan 31 2018, 11:34)  Только данные, по каждой линии отдельно. Тут есть путаница, .....хотя бы потому, что для вывода всего CRC16(CCITT) по ОДНОЙ линии требуется 16 тактов, хотя на эпюрах на это выделяется 4 такта. Неувязочка явная! Ответ на этот вопрос резко бы упростился, если кто-нибудь дал пример РЕАЛЬНОЙ последовательности в четыре провода от начала до конца.
|
|
|
|
|
Feb 2 2018, 09:22
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Мур @ Feb 2 2018, 10:49)  .....хотя бы потому, что для вывода всего CRC16(CCITT) по ОДНОЙ линии требуется 16 тактов, хотя на эпюрах на это выделяется 4 такта. Неувязочка явная! На каких эпюрах? Цитата из Physical Layer Simplified Specification Version 2.00: Цитата When the wide bus option is used, the data is transferred 4 bits at a time (refer to Figure 3-8). Start and end bits, as well as the CRC bits, are transmitted for every one of the DAT lines. CRC bits are calculated and checked for every DAT line individually.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|