Hello there, I have STMF769i Discovery 0 and I am trying to read GPIOa (it seams it has a nice patern I can observe, and has blue user button on it so I can see a bit change if I click it) into RAM with DMA triggered by a timer
What I do is setup a timer1 to trigger DMA2 (because TIM1 and TIM8 can only trigger DMA, and only DMA2 can read GPIOs) and I setup DMA to work in circular mode (DMA should read samples and I will take them out of RAM when I feal like it)
But for some reason it does not work
My timer 1 works, DMA2 Stream5 also work (I verified that by TIM1->CNT register which increase (with 2Mhz) and DMA2_Stream5->NDTR which does decrease from 16 to 0 (I want to read 16 bytes, because GPIOA has 16 pins
but when I look into GPIOA->IDR and my RAM the content should be the same but its not, its different. RAM has some random value in it (even if I clean it) while GPIO->IDR does show my User button toggle
Not sure whats wrong
here is a picture: (it seams that DMA2_Stream5->NDTR does not decrease at all on the picture, but it does, its just the I have HAL_Delay(1000); to slow the output down a bit and it seams that DMA2_Stream5->NDTR decreases to fast)
I use PRINTF_BYTE_TO_BINARY_INT16 to convert my buffer to 0 and 1 so I can see if a bit has changed
For those of you who want to quickly test it, here is a complete project:
https://www.mediafire.com/file/d2ukau99f22f6hv/STM32_F7_DMA2SRAM_Example.zip/fileI did tried to use HAL (if you define USE_REGISTERS u use registers, if you don't define this, u use HAL) but with HAL its even worse (content of DMA2_Stream5->NDTR always stays at 16)
here is the relevant part of main.c
#define SAMPLING_PORT GPIOA
#define MAX_SAMPLING_RAM 16 // Adjust buffer size as needed
#define TIM1_PERIOD 16-1 //2 MHz at the end
/* --- 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 --- */
TIM_HandleTypeDef htim1;
DMA_HandleTypeDef hdma_tim1_up;
//If I have it declared as array, then my macro does not work
uint32_t samplingRam[MAX_SAMPLING_RAM];
void ClearRAM(void)
{
for (int i = 0; i < MAX_SAMPLING_RAM; i++)
{
samplingRam[i] = 0;
}
}
ClearRAM();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
MX_DMA_Init();
/* USER CODE BEGIN 2 */
MX_USART1_UART_Init();
printf("Booting Program\n");
#ifndef USE_REGISTERS
//reading with DMA does not.....
//HAL_TIM_Base_Start(&htim1);
// DMA, circular peripheral-to-memory mode, half word (16 bit) transfer
HAL_DMA_Start(&hdma_tim1_up, (uint32_t)(&SAMPLING_PORT->IDR), (uint32_t)(samplingRam), 16);
//Enable TIM to generate DMA events
__HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_UPDATE);
//Start the timer
HAL_TIM_Base_Start(&htim1);
//HAL_TIM_OC_Start(&htim1, TIM_CHANNEL_1);
TIM1->DIER |= (1 << 8); // set UDE bit (update dma request enable)
#else
//Start DMA & Timer
DMA2->HIFCR = DMA_HIFCR_CTCIF5; //No half transfer event on stream 5
DMA2_Stream5->CR |= DMA_SxCR_EN; //Enable DMA
TIM1->CR1 |= TIM_CR1_CEN; //Start Timer
#endif
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//if (TIM1->CNT > 0)
// printf("Timer 1 is working\n");
//Blue B1 User button is on GPIOA->0 PIN (User manual page 32)
printf("---------------------\n");
printf("Buffer (Direct): "
PRINTF_BINARY_PATTERN_INT16 "\n",
PRINTF_BYTE_TO_BINARY_INT16(SAMPLING_PORT->IDR));
printf("Buffer ( RAM ): "
PRINTF_BINARY_PATTERN_INT16 "\n",
PRINTF_BYTE_TO_BINARY_INT16((uint32_t)samplingRam));
printf("---------------------\n");
printf("---------------------\n");
printf("TIM1 Counter: %d\n", TIM1->CNT);
printf("DMA Counter: %d\n", DMA2_Stream5->NDTR);
printf("---------------------\n");
HAL_Delay(1000);
}
/**
* @brief TIM1 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM1_Init(void)
{
#ifndef USE_REGISTERS
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
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_ENABLE;
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();
}
if (HAL_TIM_OC_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_TOGGLE;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
#else
//Init clock
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
TIM1->DIER = 0;
TIM1->SR &= ~TIM_SR_UIF;
TIM1->CNT = 0;
TIM1->PSC = 0;
TIM1->CR1 = TIM_CR1_URS;
TIM1->ARR = TIM1_PERIOD;
TIM1->CR2 = 0;
TIM1->DIER = TIM_DIER_UDE;
TIM1->EGR = TIM_EGR_UG;
#endif
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
#ifndef USE_REGISTERS
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
#else
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
uint32_t dmaSize = DMA_PDATAALIGN_HALFWORD;
//TIM1_UP -> DMA2, Ch6, Stream5
//DMA should be stopped before this point
DMA2_Stream5->CR = (DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_2) | dmaSize | DMA_SxCR_MINC | DMA_SxCR_CIRC;
DMA2_Stream5->M0AR = (uint32_t)samplingRam;//samplingRam;
DMA2_Stream5->PAR = (uint32_t)&(SAMPLING_PORT->IDR);
DMA2_Stream5->NDTR = 16;//transferCount;// / transferSize;
DMA2_Stream5->FCR = DMA_SxFCR_DMDIS | DMA_SxFCR_FTH;
/* DMA interrupt init */
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
#endif
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_All;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(SAMPLING_PORT, &GPIO_InitStruct); //User Button is on PIOA PIN 0
}
and here is relevant part of stm32f7xx_hal_msp.c
/* USER CODE BEGIN 1 */
#ifndef USE_REGISTERS
/**
* @brief TIM_Base MSP Initialization
* This function configures the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
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();
/* TIM2 DMA Init */
/* TIM2_UP Init */
hdma_tim1_up.Instance = DMA2_Stream5;
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_PDATAALIGN_HALFWORD;
hdma_tim1_up.Init.Mode = DMA_CIRCULAR;
hdma_tim1_up.Init.Priority = DMA_PRIORITY_HIGH;
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 */
}
}
/**
* @brief TIM_Base MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM1)
{
/* USER CODE BEGIN TIM2_MspDeInit 0 */
/* USER CODE END TIM2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM1_CLK_DISABLE();
/* TIM2 DMA DeInit */
HAL_DMA_DeInit(htim_base->hdma[TIM_DMA_ID_UPDATE]);
/* USER CODE BEGIN TIM2_MspDeInit 1 */
/* USER CODE END TIM2_MspDeInit 1 */
}
}
#endif
/* USER CODE END 1 */
I mean it doesn't relay matter what mode (HAL or registers) I get to work, would just like this to work
I do prefer to use HAL whenever possible (code is more portable and readable)
I hope someone of you can figure out whats the problem, it seams souch a simple thing to do, but its proven to be anything but simple
Thanks for Anwsering and Best Regards