Skip to main content
Visitor II
May 3, 2024
Question

STM32F429I Discovery Peripheral to Memory doesn't work at all DMA

  • May 3, 2024
  • 6 replies
  • 4207 views

Hello,

I'm trying to use interrupt + dma to capture port D data input, and the interrupt occurs but DMA is not starting to work at all.

Here is my code:

 

 

void HAL_DMA_TransferComplete(DMA_HandleTypeDef *hdma) {

if (hdma->Instance == DMA1_Stream0) {

uint8_t A1;

uint8_t CS1;

uint8_t CS2;

uint8_t data_byte = 0;

for (int i = 0; i < 8; i++) {

data_byte |= ((buffer[0] >> i) & 0x01) << i;

}

A1 = (buffer[0] >> 8) & 0x01;

CS1 = (buffer[0] >> 9) & 0x01;

CS2 = (buffer[0] >> 10) & 0x01;

if ((!CS1) && (!A1)) {

LCD1_write_cmd(data_byte);

}

if ((!CS1) && (A1)) {

LCD1_write_dat(data_byte);

}

if ((!CS2) && (!A1)) {

LCD2_write_cmd(data_byte);

}

if ((!CS2) && (A1)) {

LCD2_write_dat(data_byte);

}



}

}

// External interrupt callback function

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {



if (GPIO_Pin == GPIO_PIN_0) { // PA0 IOWR



HAL_DMA_Start_IT(&hdma_adc1 , (uint32_t)&GPIOD->IDR, (uint32_t)&buffer, 256);



}

static void MX_DMA_Init(void) {

/* DMA controller clock enable */

__HAL_RCC_DMA1_CLK_ENABLE();



/* DMA interrupt init */

HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);



/* DMA initialization code */

hdma_adc1.Instance = DMA1_Stream0;

hdma_adc1.Init.Channel = DMA_CHANNEL_0;

hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;

hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;

hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;

hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

hdma_adc1.Init.Mode = DMA_NORMAL;

hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;

hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)

{

Error_Handler();

}

}

void DMA1_Stream0_IRQHandler(void) {

HAL_DMA_IRQHandler(&hdma_adc1);

}

 

    This topic has been closed for replies.

    6 replies

    Technical Moderator
    May 3, 2024

    Hello,

    Advice: when you face an issue with something try to isolate it and do a test with a reduced code running only that feature.

    In your case do a test with a DMA transfer from GPIO to a memory nothing else. So remove LCD, EXTI etc from your code..

    Visitor II
    May 3, 2024

    @mƎALLEm 

    I isolated everything and STMCube doesn't support adding GPIO to Memory configuration, it says dma request is not available.

    I don't know what's wrong 

    Technical Moderator
    May 3, 2024

    Need to use DMA2 instead of DMA1 and configure your DMA in memory to memory direction no peripheral request here. You assume GPIOC_IDR as a memory not a peripheral:

     /* Configure DMA request hdma_memtomem_dma2_stream0 on DMA2_Stream0 */
     hdma_memtomem_dma2_stream0.Instance = DMA2_Stream0;
     hdma_memtomem_dma2_stream0.Init.Channel = DMA_CHANNEL_0;
     hdma_memtomem_dma2_stream0.Init.Direction = DMA_MEMORY_TO_MEMORY;
     hdma_memtomem_dma2_stream0.Init.PeriphInc = DMA_PINC_DISABLE;
     hdma_memtomem_dma2_stream0.Init.MemInc = DMA_MINC_ENABLE;
     hdma_memtomem_dma2_stream0.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
     hdma_memtomem_dma2_stream0.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
     hdma_memtomem_dma2_stream0.Init.Mode = DMA_NORMAL;
     hdma_memtomem_dma2_stream0.Init.Priority = DMA_PRIORITY_LOW;
     hdma_memtomem_dma2_stream0.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
     hdma_memtomem_dma2_stream0.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
     hdma_memtomem_dma2_stream0.Init.MemBurst = DMA_MBURST_SINGLE;
     hdma_memtomem_dma2_stream0.Init.PeriphBurst = DMA_PBURST_SINGLE;
     if (HAL_DMA_Init(&hdma_memtomem_dma2_stream0) != HAL_OK)
     {
     Error_Handler( );
     }
    
    HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0 , (uint32_t)&GPIOC->IDR, (uint32_t)&buffer, 256);
    

     

    Visitor II
    May 3, 2024

    @mƎALLEm 

    I'm trying to read a databus from another MCU using STM32, that solution won't be accepted. I need to capture as much data as I can. I'm capturing based on an interrupt on PA0

    Technical Moderator
    May 3, 2024

    What is the solution that won't be accepted??

    Visitor II
    May 3, 2024

    @Tesla DeLorean 

    I would like to trigger on IOWR (PINA0), and copy the data bus PORTD from PD0 to PD11

    I'm not sure which type of DMA to use

    I'm bit banging another CPU and capturing its data bus and it's 8080 Interface.

    Visitor II
    May 3, 2024
    I have to use DMA Per to Mem triggered by the timer
    The trigger to timer source, is an interrupt (IOWR) PA0
    Visitor II
    May 4, 2024

    @mƎALLEm 

    to be clear here is an example which is not working:

     

    static void MX_TIM2_Init(void)

    {

     

    /* USER CODE BEGIN TIM2_Init 0 */

     

    /* USER CODE END TIM2_Init 0 */

     

    TIM_SlaveConfigTypeDef sSlaveConfig = {0};

    TIM_MasterConfigTypeDef sMasterConfig = {0};

     

    /* USER CODE BEGIN TIM2_Init 1 */

     

    /* USER CODE END TIM2_Init 1 */

    htim2.Instance = TIM2;

    htim2.Init.Prescaler = 0;

    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

    htim2.Init.Period = 4294967295;

    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

    if (HAL_TIM_Base_Init(&htim2) != HAL_OK)

    {

    Error_Handler();

    }

    sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;

    sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;

    sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_FALLING;

    sSlaveConfig.TriggerFilter = 0;

    if (HAL_TIM_SlaveConfigSynchro(&htim2, &sSlaveConfig) != HAL_OK)

    {

    Error_Handler();

    }

    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

    if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)

    {

    Error_Handler();

    }

    /* USER CODE BEGIN TIM2_Init 2 */

    HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);

    HAL_NVIC_EnableIRQ(TIM2_IRQn);

     

    /* USER CODE END TIM2_Init 2 */

     

    }

     

    /**

    * Enable DMA controller clock

    */

    static void MX_DMA_Init(void)

    {

     

    /* DMA controller clock enable */

    __HAL_RCC_DMA1_CLK_ENABLE();

     

     

    hdma_tim2_up_ch3.Instance = DMA1_Stream5;

    hdma_tim2_up_ch3.Init.Channel = DMA_CHANNEL_3;

    hdma_tim2_up_ch3.Init.Direction = DMA_PERIPH_TO_MEMORY;

    hdma_tim2_up_ch3.Init.PeriphInc = DMA_PINC_DISABLE;

    hdma_tim2_up_ch3.Init.MemInc = DMA_MINC_ENABLE;

    hdma_tim2_up_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;

    hdma_tim2_up_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;

    hdma_tim2_up_ch3.Init.Mode = DMA_NORMAL;

    hdma_tim2_up_ch3.Init.Priority = DMA_PRIORITY_LOW;

    hdma_tim2_up_ch3.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

    if (HAL_DMA_Init(&hdma_tim2_up_ch3) != HAL_OK)

    {

    Error_Handler();

    }

     

    __HAL_LINKDMA(&htim2, hdma[TIM_DMA_ID_CC1], hdma_tim2_up_ch3);

     

    /* DMA interrupt init */

    /* DMA1_Stream1_IRQn interrupt configuration */

    HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);

    HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);

     

    }

     

    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {

     

     

    if (GPIO_Pin == GPIO_PIN_0) { // IORD

    HAL_TIM_Base_Start(&htim2);

     

    }

     

    // Timer 2 interrupt handler

    void TIM2_IRQHandler(void)

    {

    HAL_TIM_IRQHandler(&htim2);

    }

    Technical Moderator
    May 4, 2024

    Again to copy data from a gpio register to a memory you cannot do it with DMA1 but with DMA2 because from architectural point of view  DMA1 can’t do it as the mem to mem transfer is not available for it in F4 product. You can’t consider GPIO register as a peripheral but as a memory.

    Visitor II
    May 4, 2024

    @mƎALLEm 

    Thanks for clarifying.

    I get interrupt now, on PA0, but DMA is not starting. I would like as I mentioned before, to capture PORTD, because I'm doing bit banging. 

     

     

    void DMA1_Stream5_IRQHandler(void) {
    
     HAL_DMA_IRQHandler(htim2.hdma[TIM_DMA_ID_CC1]);
    
    }
    
    void TIM2_IRQHandler(void) {
    
     HAL_TIM_IRQHandler(&htim2);
    
     HAL_DMA_Start_IT(htim2.hdma[TIM_DMA_ID_CC1], (uint32_t)&(GPIOD->IDR), (uint32_t)buffer, DMA_BUFFER_SIZE);
    
    
    
    }
    /**
     * @brief TIM2 Initialization Function
     * @param None
     * @retval None
     */
    static void MX_TIM2_Init(void)
    {
    
    	 GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    	 TIM_ClockConfigTypeDef sClockSourceConfig;
    	 TIM_MasterConfigTypeDef sMasterConfig;
    	 TIM_IC_InitTypeDef sConfigIC;
    
    	 /* Peripheral clock enable */
    	 __TIM2_CLK_ENABLE();
    
    	 /* Peripheral interrupt init*/
    	 HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
    	 HAL_NVIC_EnableIRQ(TIM2_IRQn);
    
    	 /**TIM2 GPIO Configuration
    	 PA0/WKUP ------> TIM2_CH1
    	 */
    	 GPIO_InitStruct.Pin = GPIO_PIN_0;
    	 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    	 GPIO_InitStruct.Pull = GPIO_NOPULL;
    	 GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    	 GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
    	 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    	 htim2.Instance = TIM2;
    	 htim2.Init.Prescaler = 0;
    	 htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    	 htim2.Init.Period = 0xFFFFFFFF;
    	 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    	 HAL_TIM_Base_Init(&htim2);
    
    	 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    	 HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);
    
    	 HAL_TIM_IC_Init(&htim2);
    
    	 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    	 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    	 HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
    
    	 /* Input capture stuff HERE
    	 Change polarity as needed */
    	 sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
    	 sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
    	 sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
    	 sConfigIC.ICFilter = 0;
    	 HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);
    
    
    
    }
    
    /**
     * Enable DMA controller clock
     */
    static void MX_DMA_Init(void)
    {
    	 __HAL_RCC_DMA1_CLK_ENABLE();
    
    	 // DMA initialization code here
    
    	 hdma_tim2_ch1.Instance = DMA1_Stream5;
    
    	 hdma_tim2_ch1.Init.Channel = DMA_CHANNEL_3;
    
    	 hdma_tim2_ch1.Init.Direction = DMA_MEMORY_TO_MEMORY;
    
    	 hdma_tim2_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
    
    	 hdma_tim2_ch1.Init.MemInc = DMA_MINC_ENABLE;
    
    	 hdma_tim2_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    
    	 hdma_tim2_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    
    	 hdma_tim2_ch1.Init.Mode = DMA_CIRCULAR;
    
    	 hdma_tim2_ch1.Init.Priority = DMA_PRIORITY_LOW;
    
    	 hdma_tim2_ch1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    
    	 if (HAL_DMA_Init(&hdma_tim2_ch1) != HAL_OK)
    
    	 {
    
    	 Error_Handler();
    
    	 }
    
    	 __HAL_LINKDMA(&htim2, hdma[TIM_DMA_ID_CC1], hdma_tim2_ch1);
    	 HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 1);//使用中断可开启
    
    	 HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
    
    }	HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);

     

    Graduate II
    May 6, 2024

    So basically you want to capture all the I/O writes to the LCD and re-interpret those writes into equivalent commands/data for a different LCD?  If so I'm not sure a timer-and-DMA contraption is going to help all that much.

    Visitor II
    May 6, 2024

    @David Littell 

    Exactly. So which approach do you think it would work best ?

    Graduate II
    May 6, 2024

    1. Arrange the signals on the F4's pins so that minimal (or no) fiddling (shifting, ORing, etc.) is needed to translate the IOWR data.

    2. Understand fully the IOWR cycle flow and the write cycle needed by your other LCD.

    3. Write (polling) code to extract the IOWR data and synthesize the data and control signals to be written to your other LCD.  This process might be helped by a timer to generate proper control signal pulse widths as needed to your other LCD.