Полная версия этой страницы:
STM32F4 DMA+SDIO
Здравствуйте все!
У кого нибудь получалось напустить SDIO на DMA в STM32? Особенно инстресует если получалось оживить его на драйвере в комплекте HAL от ST.
У меня какой то странный глюк - в счетчие ДМА перед началом транзакции считывания 512 байт в счетчике числится 128 32 битных слов, а после - остается 4 слова (не дочитывает). В итоге прерывание не случается и все остальные беды. Какого лешего эти 4 слова остаются не вычитанными???
Dr.Alex
Apr 13 2015, 15:05
ДА.
Не первый раз удивляюсь, почему этот и другие глюки не были найдены раньше, хотя народу кто якобы уже много лет пользуется СТМ32Ф4 целая москва.
То ли все делают ёлочные гирлянды и не пишут СД через дма, то ли я лошара.
Речь о записи на СД, как я понимаю.
ДМА останавливается потому что в СДИО по непонятной причине возникает ошибка TXUNDERR (регистр STA), проверьте.
Почему-то возникает она всегда на последних 10-и словах. Само ДМА не при чём.
А лечение такое:: пишите в DLEN (SDIO) на 16+ слов больше, чем в ДМА.
А окончание записи придётся контролировать именно по завершению ДМА, прерывание от СДИО вообще запретите.
То есть, несколько функций придётся подредактировать, сейчас не скажу каких точно.
Спасибо за ответ!
У меня проблема при чтении пока, до записи банально не добрался.
Попробовал прибавить 16 к 512 в DLEN, но ситуация не сильно поменялась, в счетчике стало оставаться 3 (вместо 4).
при чем эти несчастные 16 остаются в счетчике DLEN после отработки, надо видимо еще что-то править
adnega
Apr 13 2015, 15:50
Цитата(kan35 @ Apr 13 2015, 17:26)

У кого нибудь получалось напустить SDIO на DMA в STM32?
Чтение работает как часы. Без шаманств, в строгом соответствии с документацией.
Правда, сторонними библиотеками не пользуюсь.
Могли бы вы привести код?
У меня STM32F1 все заработало можно сказать с пол пинка - и чтение и запись. А на F4 - никак. Делаю одинаково - настраиваю проект через STM32CubeMX. Поллингом проверял - работает, хотя там другие беды.
Ссылка на проект целиком ниже, я думаю запустится на любой плате с SD картой.
https://yadi.sk/d/L5v5UHt0fxMdr
Dr.Alex
Apr 13 2015, 16:49
Тоже не помню чтобы были проблемы с чтением (ДМА), но может быть просто забыл.
А прожект всё-таки лучше чистый создать и тестировать пока только функции
HAL_SD_ReadBlocks_DMA / HAL_SD_CheckReadOperation
HAL_SD_WriteBlocks_DMA / HAL_SD_CheckWriteOperation
adnega
Apr 13 2015, 18:59
Цитата(Dr.Alex @ Apr 13 2015, 19:49)

Тоже не помню чтобы были проблемы с чтением (ДМА), но может быть просто забыл.
Тут не совсем понятно в чем проблема. Проект, действительно, не маленький - разбираться очень долго.
Я бы отметил две причины, которые следует устранить:
- бывают плохие карты (фэйковые, бракованные, изношенные и т.п.);
Советую попробовать разные карты. Но раз поллингом работает, значит не оно.
- бывают медленные карты (чтение может прерываться);
Таймаут действует для ожидания данных. От момента передачи команды на чтение до появления признака готовности данных.
Чтобы порция не дочитывалась стабильно, это что-то другое.
В DMA есть битик DMA_SCR_PFCTRL, который можно (и нужно) установить только при обмене с SDIO.
Вообще, флаги ошибок о многом могут рассказать.
Dr.Alex
Apr 13 2015, 19:59
Цитата(adnega @ Apr 13 2015, 21:59)

В DMA есть битик DMA_SCR_PFCTRL, который можно (и нужно) установить только при обмене с SDIO.
HAL нигде его не ставит, и я кажыцо догадываюс почему.
Еррата запрещает ставить соответствующий битик в самом SDIO, поэтому я думаю что и в ДМА его либо нельзя ставить, либо он просто не возымеет действия без такого же битика в SDIO.
adnega
Apr 13 2015, 21:12
Цитата(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);
}
Убрал вариант влияния FATfs. Оставил только эти функции:
Код
BSP_SD_Init();
char buffer[512];
BSP_SD_ReadBlocks((uint32_t *)buffer, 0, 512, 1);
PFCTRL дейтсивтельно ни влияет. Просто NDTR начинается с 0xFFFF. И в данном случае так же не дочитывает 4 слова.
По битам - проверяю, все то же самое, см. картинку.
test
adnega
Apr 14 2015, 06:00
Считывать надо словами (DWORD 32-бита). В NDTR должно лежать количество DWORD'ов для считывания (для сектора 512 байт NDTR=128).
PBURST и PFCTRL нужно установить - помню тоже шаманил с настройками. Размеры транзакций для периферии и памяти 32-битные.
А CIRC не лишний? Зачем нужен циклический буфер?
CIRC не влияет, я отключал
А 32 битный захват данных и так включен (PSIZE=2, MSIZE = 2).
В NDTR перед началом транзакции было 0x00000080, после - 4, то есть отправилось 124 слова, кстати я в буфере вижу, что так и есть, данные из карты идут!
раньше напарывался та такой косяк, что данные были не выровнены на 4 байта, но тут все четко.
adnega
Apr 14 2015, 07:54
Цитата(kan35 @ Apr 14 2015, 09:35)

то есть отправилось 124 слова, кстати я в буфере вижу, что так и есть, данные из карты идут!
Т.е. последние 16 байт не укладываются в буфер?
Буфер смотрели? Данные не смещены?
Dr.Alex
Apr 14 2015, 08:03
Вы так и не посмотрели статус СДИО, наверняка там ошибки..
Цитата(Dr.Alex @ Apr 14 2015, 11:03)

Вы так и не посмотрели статус СДИО, наверняка там ошибки..
Посмотрел - ошибок нет во флагах. Скрин приложу чуть позже.
Данные 512 байт как будто пролетают все.
Dr.Alex
Apr 14 2015, 10:28
Посмотрел щас у себя, оказалось что читаю я всё-таки без ДМА, поскоку практически не читаю, а только пишу.
Попробовал с ДМА, нарвался на ту же фигню.
Но добавление 16-и в DLEN всё-таки меняет ситуацию, ДМА доходит до конца.
Строчка в функции HAL_SD_ReadBlocks_DMA выглядит так:
sdio_datainitstructure.DataLength = BlockSize * NumberOfBlocks + 16;
Но в целом всё равно не работает, т.к. появляются другие проблемы.
Как минимум нужно ещё поправить функцию HAL_SD_CheckReadOperation.
К сож. времени нет с этим разбираться, но вообще проблему дожать необходимо, а то говно какое-то.
UPD::
Заметил, что это прокатывет если читать более одного 512-байт сектора. Хотя бы 2.
Если читать 512 байт, то вместо 4 слов не дочитывает 3.
Dr.Alex
Apr 16 2015, 14:45
Раскапывая чибиос, обнаружил похоже ЕДИНСТВЕННУЮ комбинацию настроек ДМА и ФИФО, при которой вроде бы всё работает::
Код
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);
Неужели всё.... :-о :-о :-о
AHTOXA
Apr 16 2015, 17:21
Цитата(Dr.Alex @ Apr 16 2015, 19:45)

Неужели всё.... :-о :-о :-о
Если DMA_MDATAALIGN_WORD означает доступ по словам, то ещё не всё

Гляньте
вот этот топик.
amateur
Apr 17 2015, 16:46
Внезапно

тоже бился с недопередачей последних нескольких байт, пока не последовал примеру выше (который из чибиоса) и не выставил SDIO в качестве DMA flow controller.
Dr.Alex
Apr 17 2015, 17:12
Если бы дело было только в этом. Я этот бит раз сто ставил и убирал.
А оказалось что ВСЕ настройки должны быть только такими.
действительно, в дма должен быть выставлен peripherial flow control, burst mode по 4 слова, а так же, что не маловажно, чтобы работал стандартрный HAL драйвер нужно включить прерывание так же от SDIO и установить прерывание от него выше, чем от dma.
Вроде бы проблема решена. Хоть и не понятно, почему работает именно при таких настройках и только при таких.
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.
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.