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

Этот контроллер мне уже весь мозг вынес...

Что ему блин нужно? Может кто подскажет что-то дельное...

Итак, контроллер STM32F722... + FatFs...

проблема в чтении SD, а точнее в DMA и кэше, не хотят они никак дружить.

Все работало... проект рос... и хрясь с того ни с сего и больше не работает...

Со временем выяснилось, что перестало работать как только буферы оказались в SRAM1 (ну т.е. выше 0x20010000)...

Данные просто повреждены и все. И это реально взрыв мозга, вроде все правильно но не работает, и в то же время работает при определенных условиях,

откуда же я мог догадаться, что проблема именно в кэше, в коде ведь есть очистка но она видимо не работает,

из-за этого перебрал весь код.

 

Итак, что помогает:

1. выключение (а точнее не включение) DCache... (Но это как-то не правильно)

2. Размещение буферов в области DTCM... (Не распределять же мне теперь вручную все буферы, (от)куда идут данные)

3. Возможно поможет переход на IT вместо DMA (пока не пробовал)

 

Так вот кто-нибудь может что-то порекомендовать?

Может уже решали подобную задачу?

 

Вот функции чтения и записи

//----------------------------------------------------------------------------
//! @brief  Reads block(s) from a specified address in a card. The Data transfer
//!         is managed by DMA mode.
//! @param  pData       : Pointer to the buffer that will contain the received data
//! @param  BlockAdd    : Block Address from where data is to be read
//! @param  NumOfBlocks : Number of blocks to read.
//! @retval DRESULT: Operation result
//----------------------------------------------------------------------------
static DRESULT sd_read(void *pData, uint32_t BlockAdd, uint32_t NumOfBlocks)
{
	// Read block(s) in DMA transfer mode
	if (SD_ReadBlocks_DMA((uint32_t *)pData, BlockAdd, NumOfBlocks) == MSD_OK)
	{
		// Wait that the reading process is completed or a timeout occurs
		uint32_t flags = osEventFlagsWait(SDEventID, SD_READ_CPLT_MSG | SD_ERROR_MSG | SD_ABORT_MSG, osFlagsWaitAny, SD_TIMEOUT);
		if ((flags & (osFlagsError | SD_READ_CPLT_MSG)) == SD_READ_CPLT_MSG)
		{
			// block until SDIO IP is ready or a timeout occur 
			uint32_t tc = osKernelSysTick();
			do
			{
				if (SD_GetCardState() == SD_CARD_TRANSFER)
				{
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
					// the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address,
					// adjust the address and the D-Cache size to invalidate accordingly.
					uint32_t alignedAddr = (uint32_t)pData & ~0x1FUL;
					SCB_InvalidateDCache_by_Addr((uint32_t *)alignedAddr, NumOfBlocks * SD_BLOCKSIZE + ((uint32_t)pData - alignedAddr));
#endif
					return RES_OK;
				}
			} while ((osKernelSysTick() - tc) < SD_TIMEOUT);
		}
	}

	return RES_ERROR;
}
                                                            
//----------------------------------------------------------------------------
//! @brief  Writes block(s) to a specified address in a card. The Data transfer
//!         is managed by DMA mode.
//! @param  pData       : Pointer to the buffer that will contain the data to transmit
//! @param  BlockAdd    : Block Address where data will be written
//! @param  NumOfBlocks : Number of blocks to write
//! @retval DRESULT: Operation status
//----------------------------------------------------------------------------
static DRESULT sd_write(const void *pData, uint32_t BlockAdd, uint32_t NumOfBlocks)
{
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
	// Invalidate the chache before writting into the buffer.
	// This is not needed if the memory region is configured as W/T.
	uint32_t alignedAddr = (uint32_t)pData & ~0x1FUL;
	//SCB_InvalidateDCache_by_Addr((uint32_t *)alignedAddr, NumOfBlocks * SD_BLOCKSIZE + ((uint32_t)pData - alignedAddr));
	SCB_CleanDCache_by_Addr((uint32_t *)alignedAddr, NumOfBlocks * SD_BLOCKSIZE + ((uint32_t)pData - alignedAddr));
#endif

	// Write block(s) in DMA transfer mode
	if (SD_WriteBlocks_DMA((uint32_t *)pData, BlockAdd, NumOfBlocks) == MSD_OK)
	{
		// wait until the read operation is finished
		uint32_t flags = osEventFlagsWait(SDEventID, SD_WRITE_CPLT_MSG | SD_ERROR_MSG | SD_ABORT_MSG, osFlagsWaitAny, SD_TIMEOUT);
		if ((flags & (osFlagsError | SD_WRITE_CPLT_MSG)) == SD_WRITE_CPLT_MSG)
		{
			// block until SDIO IP is ready or a timeout occur
			uint32_t tc = osKernelSysTick();
			do
			{
				if (SD_GetCardState() == SD_CARD_TRANSFER)
				{
					return RES_OK;
				}
			} while ((osKernelSysTick() - tc) < SD_TIMEOUT);
		}
	}

	return RES_ERROR;
}
           

Пробовал Configure the MPU attributes as WT for SRAM

но это не помогает

//----------------------------------------------------------------------------
//! @brief  Configure the MPU attributes as Write Through for SRAM1/2.
//! @note   The Base Address is 0x20010000 since this memory interface is the AXI.
//!         The Region Size is 256KB, it is related to SRAM1 and SRAM2 memory size.
//! @param  None
//! @retval None
//----------------------------------------------------------------------------
static void MPU_Config(void)
{
	// Disable MPU
	LL_MPU_Disable();

	// Configure the MPU attributes as WT for SRAM
	LL_MPU_ConfigRegion(LL_MPU_REGION_NUMBER1, 0x00, 0x20010000UL,
		LL_MPU_REGION_SIZE_256KB | LL_MPU_REGION_FULL_ACCESS | LL_MPU_ACCESS_NOT_BUFFERABLE |
		MPU_ACCESS_CACHEABLE | MPU_ACCESS_NOT_SHAREABLE | LL_MPU_TEX_LEVEL1 |
		LL_MPU_INSTRUCTION_ACCESS_ENABLE);

	// Enable MPU (any access not covered by any enabled region will cause a fault)
	LL_MPU_Enable(LL_MPU_CTRL_PRIVILEGED_DEFAULT);
}

 

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


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

10 minutes ago, aaarrr said:

Дурацкий вопрос, но значение ENABLE_SD_DMA_CACHE_MAINTENANCE проверяли?

Оно установлено верно.

Я уже тоже засомневался, и не только по этому дефайну, а еще и по __DCACHE_PRESENT (что используется в SCB_CleanDCache_by_Addr())

Посмотрел в дизассемблере, все с этим ок

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


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

Не знаю, где этот дефайн должен определяться, но в приведенном коде проверка присутствует:

21 minutes ago, UniSoft said:

#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)

Поэтому и вопрос.

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


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

2 minutes ago, aaarrr said:

Не знаю, где этот дефайн должен определяться, но в приведенном коде проверка присутствует:

Поэтому и вопрос.

не сразу уловил, про какое значение говорите...

Определен верно, в коде все присутствует (смотрел в дизассемблере).

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


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

8 minutes ago, UniSoft said:

не сразу уловил, про какое значение говорите...

Определен верно, в коде все присутствует (смотрел в дизассемблере).

Понятно, просто иногда очевидные моменты выпадают из поля зрения.

 

А реализацию SCB_InvalidateDCache_by_Addr() проверяли?

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


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

При чтении подготовить область памяьи (CleanInvalidate) ДО ЧТЕНИЯ.

При записи Clean ДО ЗАПИСИ.

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


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

45 минут назад, UniSoft сказал:

(Не распределять же мне теперь вручную все буферы, (от)куда идут данные)

А почему нет? Так собственно и надо бы делать.

45 минут назад, UniSoft сказал:

Так вот кто-нибудь может что-то порекомендовать?

Покурить атрибуты областей памяти в MPU.

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


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

3 minutes ago, aaarrr said:

А реализацию SCB_InvalidateDCache_by_Addr() проверяли?

Да смотрел, а что толку... 

 

1 minute ago, GenaSPB said:

При чтении подготовить область памяьи (CleanInvalidate) ДО ЧТЕНИЯ.

При записи Clean ДО ЗАПИСИ.

Я честно говоря, не понимаю зачем нужно делать CleanInvalidate до чтения,

но (читал обсуждение) и видел в исходниках

https://github.com/micropython/micropython/blob/86f06d6a874d4eb3d6c50deec0240942344c01ea/ports/stm32/sdcard.c

И тоже пробовал ставить очистку еще и до чтения, но результата это не дало...

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


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

13 minutes ago, jcxz said:

А почему нет? Так собственно и надо бы делать.

Покурить атрибуты областей памяти в MPU.

Да это как-то странно, распределять буферы...

А если это локальные буферы? ну там прочитать заголовок файла...

можно конечно двойную буферизацию, но пока ищу нормальное решение.

 

А атрибуты памяти выкурил все в корень, все перепробовал и CACHEABLE и NOT_CACHEABLE, SHAREABLE и NOT_SHAREABLE,

LL_MPU_REGION_NUMBER0 и LL_MPU_REGION_NUMBER1 (в разных примерах по разному)

при некоторых валится в HardFault, при других ничего не меняется.

 

Прежде чем сюда написать, перепробовал все, что только мог.

Перерыл множество примеров.

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


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

До чтения. До записи. 
Перебирать долго будете.

не про атрибуты, а про доступность областей памяти для DMA, но если с выключенным data cache работает - с этим нормально.

 

Если что - вот идеально работающий на F7 вариант. https://github.com/ua1arn/hftrx/blob/master/sdcard.c

Смотреть SD_disk_read и SD_disk_write

Изменено пользователем GenaSPB

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


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

1 hour ago, GenaSPB said:

Если что - вот идеально работающий на F7 вариант

// ?????? HF Dream Receiver (?? ??????? ?????)

Там наверное что-то важное было... До автоматической смены кодировки.

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


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

Нет.... скачайте и смотритте в нужной кодировке.

Обычнам  cp1251

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


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

4 hours ago, GenaSPB said:

Если что - вот идеально работающий на F7 вариант. https://github.com/ua1arn/hftrx/blob/master/sdcard.c

Смотреть SD_disk_read и SD_disk_write

 

Посмотрел, к сожалению, ничего нового не увидел.

Единственное, что очистка кэша до чтения... хотя я это и не понимаю, но как уже сказал, такой вариант пробовал... не помогло.

А на счет идеально работающий, это еще не факт... 

ради интереса, разместите буфер куда-нибудь за пределы DTCM... 

ну, например вот так:

#define __AT(__ADDR)     __attribute__((section(".ARM.__at_" #__ADDR)))
#define AT_ADDR(__ADDR)  __AT(__ADDR)

AT_ADDR(0x20010200) static RAMNOINIT_D1 FATFS wave_Fatfs;

 

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


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

Мы про F7 говорим? Все USB буферы у меня исключительно ВНЕ DTCM размещаются. В DTCM кладу то что требует скоростной работы... Сделано через LD скрипт, в DTCM попадает .data - инициализированные переменные. Скрипт там же.

Могу посоветовать проверить выравнивание адресов для обмена - в структурах FatFS это не гарантируется.

У меня превышен размер допустимых аттачментов на 17%, а так бы MAP файл заскриншотил бы...

 

Там вот так:

 .bss           0x20025ae8        0x0 c:/program files (x86)/gnu tools arm embedded/7 2018-q2-update/bin/../lib/gcc/arm-none-eabi/7.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m/fpv4-sp/hard\libc.a(lib_a-strlen.o)
 *(COMMON)
                0x20025b00                . = ALIGN (0x20)
 *fill*         0x20025ae8       0x18 
                0x20025b00                __bss_end__ = .

.noinit         0x20025b00    0x110c0
                0x20025b00                . = ALIGN (0x20)
 *(.noinit)
 .noinit        0x20025b00       0x40 C:\Users\gena\AppData\Local\Temp\ccCriE8j.ltrans0.ltrans.o
 .noinit        0x20025b40    0x10e40 C:\Users\gena\AppData\Local\Temp\ccCriE8j.ltrans2.ltrans.o
                0x20026540                wave_Fatfs.lto_priv.478
 .noinit        0x20036980      0x240 C:\Users\gena\AppData\Local\Temp\ccCriE8j.ltrans4.ltrans.o
                0x20036980                wav_file.lto_priv.480
                0x20036bc0                . = ALIGN (0x20)

.heap           0x20036bc0        0x0
                0x20036bc0                __HeapBase = .
                0x20036bc0                __end__ = .
                0x20036bc0                end = __end__
 *(.heap*)
                0x20036bc0                __HeapLimit = .
 

Изменено пользователем GenaSPB

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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