Hi there, I am playing with GPIOs on my STM32s and today wanted to create an example on how to read GPIO rail on my STM32H750B-DK like I already did for my STM32F769, which you can download here: ttps://www.mediafire.com/file/n8h3c617olsmqlu/STM32_F7_DMA2SRAM_Example.zip/file
What I am doing is this
Here are my definitions and macros
/* --- PRINTF_BYTE_TO_BINARY macro's --- */
#define PRINTF_BINARY_SEPARATOR
#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c"
#define PRINTF_BYTE_TO_BINARY_INT8(i) \
(((i) & 0x80ll) ? '1' : '0'), \
(((i) & 0x40ll) ? '1' : '0'), \
(((i) & 0x20ll) ? '1' : '0'), \
(((i) & 0x10ll) ? '1' : '0'), \
(((i) & 0x08ll) ? '1' : '0'), \
(((i) & 0x04ll) ? '1' : '0'), \
(((i) & 0x02ll) ? '1' : '0'), \
(((i) & 0x01ll) ? '1' : '0')
#define PRINTF_BINARY_PATTERN_INT16 \
PRINTF_BINARY_PATTERN_INT8 PRINTF_BINARY_SEPARATOR PRINTF_BINARY_PATTERN_INT8
#define PRINTF_BYTE_TO_BINARY_INT16(i) \
PRINTF_BYTE_TO_BINARY_INT8((i) >> 8), PRINTF_BYTE_TO_BINARY_INT8(i)
#define PRINTF_BINARY_PATTERN_INT32 \
PRINTF_BINARY_PATTERN_INT16 PRINTF_BINARY_SEPARATOR PRINTF_BINARY_PATTERN_INT16
#define PRINTF_BYTE_TO_BINARY_INT32(i) \
PRINTF_BYTE_TO_BINARY_INT16((i) >> 16), PRINTF_BYTE_TO_BINARY_INT16(i)
#define PRINTF_BINARY_PATTERN_INT64 \
PRINTF_BINARY_PATTERN_INT32 PRINTF_BINARY_SEPARATOR PRINTF_BINARY_PATTERN_INT32
#define PRINTF_BYTE_TO_BINARY_INT64(i) \
PRINTF_BYTE_TO_BINARY_INT32((i) >> 32), PRINTF_BYTE_TO_BINARY_INT32(i)
/* --- end macros --- */
#define SAMPLING_PORT GPIOC
#define MAX_SAMPLING_RAM 16*2 // Adjust buffer size as needed
#define SAMPLES_TO_CAPTURE 16
#define TIM1_PERIOD 16-1 //2 MHz at the end
1. Setup TIM1 that will trigger DMA with 2Mhz interval (this works fine)
static void MX_TIM1_Init(void)
{
/* Peripheral clock enable */
__HAL_RCC_TIM1_CLK_ENABLE();
/* USER CODE BEGIN TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = TIM1_PERIOD;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
2. Setup DMA1_Stream1 (in STM32H7 every DMA has access to GPIO ports exept DMA1_Stream0 (which is only for ADC)
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM1)
{
/* USER CODE BEGIN TIM2_MspInit 0 */
/* USER CODE END TIM2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM1_CLK_ENABLE();
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_tim1_up.Instance = DMA1_Stream1; //DMA1_Stream0 can only be used for reading from ADC, DMA1_Stream1 can be used for other things besides reading ADC
hdma_tim1_up.Init.Request = DMA_REQUEST_TIM1_UP;
//hdma_tim1_up.Init.Direction = DMA_MEMORY_TO_MEMORY;
hdma_tim1_up.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_tim1_up.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim1_up.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim1_up.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_tim1_up.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_tim1_up.Init.Mode = DMA_CIRCULAR;
//hdma_tim1_up.Init.Mode = DMA_NORMAL;
hdma_tim1_up.Init.Priority = DMA_PRIORITY_HIGH;
//hdma_tim1_up.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_tim1_up.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_tim1_up.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_tim1_up.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_tim1_up.Init.PeriphBurst = DMA_PBURST_SINGLE;
if (HAL_DMA_Init(&hdma_tim1_up) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_UPDATE], hdma_tim1_up);
/* USER CODE BEGIN TIM2_MspInit 1 */
/* USER CODE END TIM2_MspInit 1 */
}
}
3. Read GPIOC->IDR and compare if its value is the same as in RAM, if it is, then it works, if its not, then it doesn't work
static uint32_t samplingRam[MAX_SAMPLING_RAM] __attribute__ ((section(".RAM_D1"))) __attribute__ ((aligned (4)));
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
//Clean cache
memset(&samplingRam[0], 0x00, sizeof(samplingRam)); //This buffer should have ... when DMA is working and 0x00 when DMA is not working
SCB_CleanDCache_by_Addr((uint32_t*)&samplingRam[0], sizeof(samplingRam));
// DMA, circular peripheral-to-memory mode, half word (16 bit) transfer
if (HAL_DMA_Start_IT(&hdma_tim1_up, (uint32_t)(&SAMPLING_PORT->IDR), (uint32_t)(samplingRam), 16) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}
//Enable TIM to generate DMA events
__HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_UPDATE);
/*##-2- Start the TIM Base generation in interrupt mode ####################*/
/* Start Channel1 */
if (HAL_TIM_Base_Start_IT(&htim1) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}
while (1)
{
//if (isTransfering)
//{
/* USER CODE END WHILE */
SCB_InvalidateDCache_by_Addr((uint32_t*)&samplingRam[0], sizeof(samplingRam));
SCB_CleanDCache_by_Addr((uint32_t*)&samplingRam[0], sizeof(samplingRam));
/* USER CODE BEGIN 3 */
printf("---------------------\n");
printf("RAM Adress is: %p\n", samplingRam);
printf("---------------------\n");
printf("---------------------\n");
printf("Buffer (Direct): "
PRINTF_BINARY_PATTERN_INT16 "\n",
PRINTF_BYTE_TO_BINARY_INT16(SAMPLING_PORT->IDR));
for (int i = 0; i < SAMPLES_TO_CAPTURE; i += 16)
{
printf("Buffer ( RAM ): " PRINTF_BINARY_PATTERN_INT16 "\n", PRINTF_BYTE_TO_BINARY_INT16(samplingRam[i]));
}
printf("---------------------\n");
printf("---------------------\n");
printf("TIM1 Counter: %d\n", TIM1->CNT);
printf("DMA Counter: %d\n", DMA1_Stream1->NDTR);
printf("---------------------\n");
//}
HAL_Delay(1000);
}
Now unlike STM32F7 where everything works now, STM32H7 uses D and I cache, which complicated my GPIO read example a lot
and yes, I did try to copy data from one buffer that is located in D1 into another buffer, which is located in D2 RAM, and this works fine
So as you can see from the picture:
Content of GPIOC->IDR and my RAM is not the same (it looks like its cached, eve if I invalidated and cleaned the cache with
SCB_InvalidateDCache_by_Addr((uint32_t*)&samplingRam[0], sizeof(samplingRam));
SCB_CleanDCache_by_Addr((uint32_t*)&samplingRam[0], sizeof(samplingRam));
For some strange reason, even if I disable the cache, with
SCB_DisableICache();
SCB_DisableDCache();
it still doesn't work
So really not sure what the problem is here
I know DMA is doing something, because if I never start the timer or DMA, then content of my ram is 0 (just like I told it to be)
So I hope someone has some idea what would the problem be, because this seems to be so simple example (because the same example (-D and I cache, and using DMA2 there because only DMA2 has access to GPIO on STM32F7) work fine on my STM32F7 board, so what is different on STMH7 board that my example doesn't work
PS: I am using HAL, because I want my examples to be as portable and as easy to read as possible, so thats why if I can I always try to make them in HAL
PPS: If anyone wants to play with my broken example, its here:
https://www.mediafire.com/file/uxe7j1teqko0jxf/STM32_H7_DMA2SRAM_Example.zip/fileThanks for Answering and Best Regards