cancel
Showing results for 
Search instead for 
Did you mean: 

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

Ahmed Tolba
Associate II

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] >> 😎 & 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);

}

 

22 REPLIES 22

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.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

@SofLit 

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);

 

What TIM2 is doing here? To trigger DMA transfers?
As stated by @Tesla DeLorean you need to provide a sketch or diagram of what you want to do. Arguing by just sharing a code without a detailed description of your application is not an efficient way to help you.

Thank you for your understanding.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

 

@SofLit 

@Tesla DeLorean 

I'm trying to capture the signals as shown in that socket using STM32F429I. That socket communicates from a CPU to another LCD. The STM32 is acting as man in the middle, so I will forward these signals to another LCD of my own.

So My idea not sure if its correct or not, is to use Timer2 as a trigger, and acting on IOWR (PA0), I should start DMA transfer, and copy the data bus (latch, all signals) save them in a buffer and process them.

FNRdd (2).jpg

UEJJ0.png

Here is a detailed reply:

 

Following with that great answer Reverse engineer LCD Protocol used in MPC2000XL

I'm trying to capture the data using stm32, it appears that I need to use DMA with Parallel Input. I have setup Timer2 channel 1 with trigger on IOWRD(PA0), and wanted to start a dma transfer. I can capture the IOWR falling edge signal using the following code, but DMA never starts. I'm trying to copy the GPIOD to memory, then I can process that buffer.

Here is the configuration:

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);

}
void HAL_DMA_XferCpltCallback(DMA_HandleTypeDef *hdma)
{
    if (hdma->Instance == DMA2_Stream2)
    {
        // DMA transfer complete callback code here
    }
}
// DMA interrupt handler
void DMA2_Stream2_IRQHandler(void) {
    HAL_DMA_IRQHandler(htim2.hdma[TIM_DMA_ID_CC1]);
}
void XferCpltCallback(DMA_HandleTypeDef *hdma)
{
    if (hdma->Instance == DMA1_Stream5) {
        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);
        }

    }
}
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);



}

static void MX_DMA_Init(void)
{
    __HAL_RCC_DMA1_CLK_ENABLE();


    // DMA initialization code here

    hdma_tim2_ch1.Instance = DMA2_Stream2;

    hdma_tim2_ch1.Init.Channel = DMA_CHANNEL_6;

    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_BYTE ; /* only reading in GPIO PB[15:8]... PB[7:0] used on FSMC */
    hdma_tim2_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD ;
    hdma_tim2_ch1.Init.Mode = DMA_NORMAL;  /* double memory buffer used */
    hdma_tim2_ch1.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_tim2_ch1.Init.FIFOMode = DMA_FIFOMODE_DISABLE; /* using FIFO mode since memory datasize=32bit and GPIO=8bits in our case */

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

    if (HAL_DMA_Init(htim2.hdma[TIM_DMA_ID_CC1]) != HAL_OK)

    {

        Error_Handler();

    }

    HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 1);

    HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);


}
 

@SofLit @Tesla DeLorean 

Any feedback will be appreciated 

@SofLit @Tesla DeLorean 

 

So I want to setup

1. Timer with DMA trigger using Input Pin for example timer 8 has PC6, at falling edge

2. Repetitive trigger DMA to transfer data from PORTD to Memory

3. Once count is finished, and PC6 is induced again, it trigger N DMA transfers.

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.

@David Littell 

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

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.