|
STM32F4 DMA+SDIO, на основе Cube HAL |
|
|
|
Apr 13 2015, 15:05
|
Профессионал
    
Группа: Свой
Сообщений: 1 386
Регистрация: 5-04-05
Из: моська, RF
Пользователь №: 3 863

|
ДА. Не первый раз удивляюсь, почему этот и другие глюки не были найдены раньше, хотя народу кто якобы уже много лет пользуется СТМ32Ф4 целая москва. То ли все делают ёлочные гирлянды и не пишут СД через дма, то ли я лошара.
Речь о записи на СД, как я понимаю. ДМА останавливается потому что в СДИО по непонятной причине возникает ошибка TXUNDERR (регистр STA), проверьте. Почему-то возникает она всегда на последних 10-и словах. Само ДМА не при чём.
А лечение такое:: пишите в DLEN (SDIO) на 16+ слов больше, чем в ДМА. А окончание записи придётся контролировать именно по завершению ДМА, прерывание от СДИО вообще запретите. То есть, несколько функций придётся подредактировать, сейчас не скажу каких точно.
Сообщение отредактировал IgorKossak - Apr 13 2015, 16:10
|
|
|
|
|
Apr 13 2015, 18:59
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(Dr.Alex @ Apr 13 2015, 19:49)  Тоже не помню чтобы были проблемы с чтением (ДМА), но может быть просто забыл. Тут не совсем понятно в чем проблема. Проект, действительно, не маленький - разбираться очень долго. Я бы отметил две причины, которые следует устранить: - бывают плохие карты (фэйковые, бракованные, изношенные и т.п.); Советую попробовать разные карты. Но раз поллингом работает, значит не оно. - бывают медленные карты (чтение может прерываться); Таймаут действует для ожидания данных. От момента передачи команды на чтение до появления признака готовности данных. Чтобы порция не дочитывалась стабильно, это что-то другое. В DMA есть битик DMA_SCR_PFCTRL, который можно (и нужно) установить только при обмене с SDIO. Вообще, флаги ошибок о многом могут рассказать.
|
|
|
|
|
Apr 13 2015, 21:12
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(Dr.Alex @ Apr 13 2015, 22:59)  HAL нигде его не ставит, и я кажыцо догадываюс почему. Еррата запрещает ставить соответствующий битик в самом SDIO, поэтому я думаю что и в ДМА его либо нельзя ставить, либо он просто не возымеет действия без такого же битика в SDIO. Errata описывает только SDIO HW flow control, но я его и не использую. На DMA это не влияет. Еще один нужный битик DMA_SCR_PBURST. У меня такой код (обработку ошибок и нестандартного поведения не привожу): CODE Перед считыванием данных я проверяю статус (CMD13) - если карта в TRAN, то буду считывать:
else if(cs.current_state == CARD_STATE_TRAN) { SDIO->DCTRL = 0; SDIO->DLEN = sdio_p_buf_size; DMA2_Stream6->CR = 0 | (4 << DMA_SCR_CHSEL) | (1 << DMA_SCR_MINC) | (2 << DMA_SCR_MSIZE) | (2 << DMA_SCR_PSIZE) | (1 << DMA_SCR_PBURST) | (1 << DMA_SCR_PFCTRL) | (0 << DMA_SCR_EN); DMA2_Stream6->FCR = 0 | (1 << DMA_SFCR_DMDIS) | (1 << DMA_SFCR_FTH); DMA2->HIFCR = (0x3D << 16); DMA2_Stream6->PAR = (DWORD)&SDIO->FIFO; DMA2_Stream6->M0AR = (DWORD)sdio_p_buf; DMA2_Stream6->NDTR = sdio_p_buf_size / sizeof(DWORD); sdio_fsm = SDIO_FSM_READ; SDIO_Send(CMD18_READ_MULTIPLE_BLOCK, (sdio_sect << ((card_type == CARD_SDHC)? 0 : 9)), EXPECT_SHORT_RESP); }
когда CMD18 выполнится запускаю прием данных так:
DMA2_Stream6->CR = 0 | (4 << DMA_SCR_CHSEL) | (1 << DMA_SCR_MINC) | (2 << DMA_SCR_MSIZE) | (2 << DMA_SCR_PSIZE) | (1 << DMA_SCR_PBURST) | (1 << DMA_SCR_PFCTRL) | (1 << DMA_SCR_EN); SDIO->DCTRL = 0 | (9 << SDIO_DCTRL_DBLOCKSIZE) | (1 << SDIO_DCTRL_DTDIR) | (1 << SDIO_DCTRL_DMAEN) | (1 << SDIO_DCTRL_DTEN);
по приходу прерывания DATAEND отправляю "горшочек не вари" для CMD18:
if(status & (1 << SDIO_DATAEND)) { SDIO->ICR = (1 << SDIO_DATAEND); SDIO->DCTRL = 0; sdio_fsm = SDIO_FSM_READ_STOP; SDIO_Send(CMD12_STOP_TRANSMISSION, NO_ARGUMENTS, EXPECT_SHORT_RESP); }
|
|
|
|
|
Apr 14 2015, 05:52
|
Знающий
   
Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594

|
Убрал вариант влияния FATfs. Оставил только эти функции: Код BSP_SD_Init(); char buffer[512]; BSP_SD_ReadBlocks((uint32_t *)buffer, 0, 512, 1); PFCTRL дейтсивтельно ни влияет. Просто NDTR начинается с 0xFFFF. И в данном случае так же не дочитывает 4 слова. По битам - проверяю, все то же самое, см. картинку. test
Эскизы прикрепленных изображений
|
|
|
|
|
Apr 14 2015, 06:35
|
Знающий
   
Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594

|
CIRC не влияет, я отключал А 32 битный захват данных и так включен (PSIZE=2, MSIZE = 2). В NDTR перед началом транзакции было 0x00000080, после - 4, то есть отправилось 124 слова, кстати я в буфере вижу, что так и есть, данные из карты идут!
раньше напарывался та такой косяк, что данные были не выровнены на 4 байта, но тут все четко.
|
|
|
|
|
Apr 14 2015, 08:37
|
Знающий
   
Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594

|
Цитата(Dr.Alex @ Apr 14 2015, 11:03)  Вы так и не посмотрели статус СДИО, наверняка там ошибки.. Посмотрел - ошибок нет во флагах. Скрин приложу чуть позже. Данные 512 байт как будто пролетают все.
|
|
|
|
|
Apr 14 2015, 10:28
|
Профессионал
    
Группа: Свой
Сообщений: 1 386
Регистрация: 5-04-05
Из: моська, RF
Пользователь №: 3 863

|
Посмотрел щас у себя, оказалось что читаю я всё-таки без ДМА, поскоку практически не читаю, а только пишу. Попробовал с ДМА, нарвался на ту же фигню. Но добавление 16-и в DLEN всё-таки меняет ситуацию, ДМА доходит до конца. Строчка в функции HAL_SD_ReadBlocks_DMA выглядит так: sdio_datainitstructure.DataLength = BlockSize * NumberOfBlocks + 16; Но в целом всё равно не работает, т.к. появляются другие проблемы. Как минимум нужно ещё поправить функцию HAL_SD_CheckReadOperation. К сож. времени нет с этим разбираться, но вообще проблему дожать необходимо, а то говно какое-то.
UPD:: Заметил, что это прокатывет если читать более одного 512-байт сектора. Хотя бы 2. Если читать 512 байт, то вместо 4 слов не дочитывает 3.
|
|
|
|
|
Apr 16 2015, 14:45
|
Профессионал
    
Группа: Свой
Сообщений: 1 386
Регистрация: 5-04-05
Из: моська, RF
Пользователь №: 3 863

|
Раскапывая чибиос, обнаружил похоже ЕДИНСТВЕННУЮ комбинацию настроек ДМА и ФИФО, при которой вроде бы всё работает:: Код hdma_sdio.Instance = DMA2_Stream6; hdma_sdio.Init.Channel = DMA_CHANNEL_4; hdma_sdio.Init.Direction = DMA_MEMORY_TO_PERIPH;//DMA_PERIPH_TO_MEMORY hdma_sdio.Init.PeriphInc = DMA_PINC_DISABLE; hdma_sdio.Init.MemInc = DMA_MINC_ENABLE; hdma_sdio.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_sdio.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; hdma_sdio.Init.Mode = DMA_PFCTRL; hdma_sdio.Init.Priority = DMA_PRIORITY_LOW; // Единственное что не имеет значения hdma_sdio.Init.FIFOMode = DMA_FIFOMODE_ENABLE; hdma_sdio.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; hdma_sdio.Init.MemBurst = DMA_MBURST_INC4; hdma_sdio.Init.PeriphBurst = DMA_PBURST_INC4; HAL_DMA_Init(&hdma_sdio);
__HAL_LINKDMA(hsd,hdmarx,hdma_sdio); __HAL_LINKDMA(hsd,hdmatx,hdma_sdio); Неужели всё.... :-о :-о :-о
|
|
|
|
|
Apr 17 2015, 16:46
|
Участник

Группа: Участник
Сообщений: 17
Регистрация: 25-03-07
Пользователь №: 26 489

|
Внезапно  тоже бился с недопередачей последних нескольких байт, пока не последовал примеру выше (который из чибиоса) и не выставил SDIO в качестве DMA flow controller.
|
|
|
|
|
Apr 18 2015, 05:08
|
Знающий
   
Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594

|
действительно, в дма должен быть выставлен peripherial flow control, burst mode по 4 слова, а так же, что не маловажно, чтобы работал стандартрный HAL драйвер нужно включить прерывание так же от SDIO и установить прерывание от него выше, чем от dma. Вроде бы проблема решена. Хоть и не понятно, почему работает именно при таких настройках и только при таких.
Эскизы прикрепленных изображений
|
|
|
|
|
Apr 29 2015, 14:00
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672

|
SDIO+DMA FEIF error.I didn't find any way to avoid this error but ignoring it. I wasn't the first one of doing so. There is an example from Keil: .\Keil\ARM\Boards\Keil\MCBSTM32F400\RL\FlashFS\SD_File\SDIO_STM32F4xx.c Код static BOOL WriteBlock (U32 bl, U8 *buf, U32 cnt) { /* Write a cnt number of 512 byte blocks to Flash Card. */ U32 i;
SDIO->DLEN = cnt * 512; SDIO->DTIMER = cnt * DATA_WR_TOUT_VALUE; SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DTEN ;
for (i = DMA_TOUT; i; i--) { if (DMA2->LISR & DMA_LISR_TEIF3) { break; } if (DMA2->LISR & DMA_LISR_TCIF3) { if ((SDIO->STA & (SDIO_STA_DBCKEND|SDIO_STA_DATAEND)) == (SDIO_STA_DBCKEND|SDIO_STA_DATAEND)) { /* Data transfer finished. */ return (__TRUE); } } } /* DMA Transfer timeout. */ return (__FALSE); } If you look inside their for loop they just ignoring FEIF. I verified that card access works (at least every time I've tried) and as I stated before I don't know any way to avoid this error. STM errata doesn't shed light on this issue or I didn't find it... Does anyone knows better way to deal with this issue? Thank you in advance.
Сообщение отредактировал pitt - Apr 30 2015, 01:36
--------------------
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|