www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32: Seriell senden via DMA funktioniert zwar, aber wo wird´s gestartet?


Autor: Fun Rice (funnyrice)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

habe hier einen erweiterten Beispielcode in dem nach dem Einschalten 
seriell via DMA gesendet wird. Soweit funktioniert es.
Nun wollte ich einfach den gleichen String, nach Joystickbetätigung 
(Primer2), nochmal senden. Die Joysick-Funktion funktioniert auch und 
habe dort den Code eingefügt.
          /* USARTz TX DMA1 Channel (triggered by USARTz Tx event) Config */
        DMA_DeInit(USARTz_Tx_DMA_Channel);  
        DMA_InitStructure.DMA_PeripheralBaseAddr = USARTz_DR_Base;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer2;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
        DMA_InitStructure.DMA_BufferSize = TxBufferSize2;  
        DMA_Init(USARTz_Tx_DMA_Channel, &DMA_InitStructure);

Leider wird nach Aufrufen der Funktion der String kein zweites Mal 
gesendet?!?

Wo ist denn mein Denkfehler?
Hab die ganze Code mal angehangen.

MfG
FunRice

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "platform_config.h"
#include "stm32f10x_dma.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_it.h"
#include "stm32f10x_flash.h"
#include "stm32f10x_tim.h"
#include "lib_dbg.h"

/** @addtogroup STM32F10x_StdPeriph_Examples
  * @{
  */

/** @addtogroup USART_DMA_Polling
  * @{
  */ 

/* Private typedef -----------------------------------------------------------*/
typedef enum { FAILED = 0, PASSED = !FAILED} TestStatus;

/* Private define ------------------------------------------------------------*/
#define DEBUG

#define TxBufferSize1   (countof(TxBuffer1) - 1)
#define TxBufferSize2   (countof(TxBuffer2) - 1)

//LEDs port and pins
#define LEDS_GPIO       (GPIOE)
#define LEDS_RCC_GPIO   (RCC_APB2Periph_GPIOE)
#define LED0_PIN        (GPIO_Pin_0)
#define LED1_PIN        (GPIO_Pin_1)
#define LEDS_BOTH_PINS  (LED0_PIN|LED1_PIN)

//joystick port and pins
#define JSTK_GPIO       (GPIOE)
#define JSTK_RCC_GPIO   (RCC_APB2Periph_GPIOE)
#define JSTK_LEFT_PIN   (GPIO_Pin_3)
#define JSTK_RIGHT_PIN  (GPIO_Pin_4)
#define JSTK_UP_PIN     (GPIO_Pin_5)
#define JSTK_DOWN_PIN   (GPIO_Pin_6)
#define JSTK_ALL_PINS   (JSTK_LEFT_PIN|JSTK_RIGHT_PIN|JSTK_UP_PIN|JSTK_DOWN_PIN)

//push button port and pin
#define BP_GPIO         (GPIOA)
#define BP_RCC_GPIO     (RCC_APB2Periph_GPIOA)
#define BP_PIN          (GPIO_Pin_8)


//LCD backlight enable port and pin
#define LCDBLEN_GPIO         (GPIOB)
#define LCDBLEN_RCC_GPIO     (RCC_APB2Periph_GPIOB)
#define LCDBLEN_PIN          (GPIO_Pin_8)





/* Private macro -------------------------------------------------------------*/
#define countof(a)   (sizeof(a) / sizeof(*(a)))

/* Private variables ---------------------------------------------------------*/
USART_InitTypeDef USART_InitStructure;
uint8_t TxBuffer1[] = "1 USART DMA Polling: USARTy -> USARTz using DMA";
uint8_t TxBuffer2[] = "2 USART DMA Polling: USARTz -> USARTy using DMA";
uint8_t RxBuffer1[TxBufferSize2];
uint8_t RxBuffer2[TxBufferSize1];
volatile TestStatus TransferStatus1 = FAILED;
volatile TestStatus TransferStatus2 = FAILED; 
ErrorStatus HSEStartUpStatus; 

vu16 CCR1_Val = 480;
vu16 CCR2_Val = 32768;
vu16 CCR3_Val = 16384;
vu16 CCR4_Val = 8192; 

u16     u16ActInputGPIOE = 0;
u16     u16PreInputGPIOE = 0;
u16     u16DeboInputGPIOE = 0;
u16     u16InvertRegGPIOE = 0;
u16     u16FallInputGPIOE = 0;
u16     u16RiseInputGPIOE = 0;

volatile bool bTimer2Ch1Int = 0; 



/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void USART_Configuration(void);
void DMA_Configuration(void);
void NVIC_Configuration(void);
void TIM2_Configuration(void);
void GetGPIOE(void);
void PinChangeGPIOE(void);

void MainLoop(void);
void MainFunction(void);

TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);

/* Private functions ---------------------------------------------------------*/

/**
  * @brief   Main program
  * @param  None
  * @retval None
  */
int main(void)
{
#ifdef DEBUG
  debug();
#endif 

  /* System Clocks Configuration */
  RCC_Configuration();
  NVIC_Configuration();
  /* Configure the GPIO ports */
  GPIO_Configuration();

  /* Configure the DMA */
  DMA_Configuration();
  USART_Configuration();
  TIM2_Configuration(); 

    MainLoop();

 while(1){};
  }

void MainLoop(void)
{
while(1)
    {
     if(bTimer2Ch1Int)
        {
         bTimer2Ch1Int = 0;
        

  
        //MainFunction();
         GetGPIOE();
        }
    }
}
void MainFunction(void)
{
 GetGPIOE();
  /* Wait until USARTy TX DMA1 Channel Transfer Complete */
  while (DMA_GetFlagStatus(USARTy_Tx_DMA_FLAG) == RESET)
  {
  }

  /* Wait until USARTy RX DMA1 Channel Transfer Complete */
  while (DMA_GetFlagStatus(USARTy_Rx_DMA_FLAG) == RESET)
  {
  }

  /* Wait until USARTz TX DMA1 Channel Transfer Complete */
  while (DMA_GetFlagStatus(USARTz_Tx_DMA_FLAG) == RESET)
  {
  }
//GPIO_WriteBit(GPIOB, GPIO_Pin_6, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_6)));

  /* Wait until USARTz RX DMA1 Channel Transfer Complete */
  while (DMA_GetFlagStatus(USARTz_Rx_DMA_FLAG) == RESET)
  {
  }
GPIO_WriteBit(GPIOB, GPIO_Pin_6, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_6)));

  /* Check the received data with the send ones */
  TransferStatus1 = Buffercmp(TxBuffer2, RxBuffer1, TxBufferSize2);
  /* TransferStatus1 = PASSED, if the data transmitted from USARTz and  
     received by USARTy are the same */
  /* TransferStatus1 = FAILED, if the data transmitted from USARTz and 
     received by USARTy are different */
  TransferStatus2 = Buffercmp(TxBuffer1, RxBuffer2, TxBufferSize1);
  /* TransferStatus2 = PASSED, if the data transmitted from USARTy and  
     received by USARTz are the same */
  /* TransferStatus2 = FAILED, if the data transmitted from USARTy and 
     received by USARTz are different */

  while (1)
  {
  }
}

/**
  * @brief  Configures the different system clocks.
  * @param  None
  * @retval None
  */

void GetGPIOE()
{
 u16FallInputGPIOE = 0;
 u16RiseInputGPIOE = 0;

 u16PreInputGPIOE = u16ActInputGPIOE;
 u16ActInputGPIOE = ((u16)JSTK_GPIO->IDR) & ( JSTK_ALL_PINS );
 //u16ActInputGPIOE = ( (GPIO_ReadInputData(JSTK_GPIO))  );
 u16ActInputGPIOE ^= u16InvertRegGPIOE;

 if(u16ActInputGPIOE == u16PreInputGPIOE)
    {    
     if(u16DeboInputGPIOE != u16PreInputGPIOE)
        {
         u16FallInputGPIOE = u16DeboInputGPIOE;
         u16FallInputGPIOE ^= u16ActInputGPIOE;
         u16RiseInputGPIOE = u16FallInputGPIOE;
         u16FallInputGPIOE &= u16DeboInputGPIOE;
         u16RiseInputGPIOE &= u16ActInputGPIOE;
         u16DeboInputGPIOE = u16PreInputGPIOE;
     
         PinChangeGPIOE();
     
        }
    }
}

void PinChangeGPIOE()
{
DMA_InitTypeDef DMA_InitStructure;

    if(u16RiseInputGPIOE& JSTK_UP_PIN) 
        {
          /* USARTz TX DMA1 Channel (triggered by USARTz Tx event) Config */
        DMA_DeInit(USARTz_Tx_DMA_Channel);  
        DMA_InitStructure.DMA_PeripheralBaseAddr = USARTz_DR_Base;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer2;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
        DMA_InitStructure.DMA_BufferSize = TxBufferSize2;  
        DMA_Init(USARTz_Tx_DMA_Channel, &DMA_InitStructure);
        
        // Nur als Funktionstest
        GPIO_SetBits(GPIOE, GPIO_Pin_0);
    }

        if(u16RiseInputGPIOE& JSTK_DOWN_PIN)
        GPIO_ResetBits(GPIOE, GPIO_Pin_0);
    
    GPIO_WriteBit(GPIOE, GPIO_Pin_1, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOE, GPIO_Pin_1)));

}

void RCC_Configuration(void)
{

  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration -----------------------------*/   
  /* RCC system reset(for debug purpose) */
  RCC_DeInit();

  /* DMA clock enable */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);

  /* Wait till HSE is ready */
  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if (HSEStartUpStatus == SUCCESS)
  {
    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);
 
    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1); 
  
    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1); 

    /* PCLK1 = HCLK/2 */
    RCC_PCLK1Config(RCC_HCLK_Div2);

    /* PLLCLK = 12MHz * 6 = 72 MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6);

    /* Enable PLL */ 
    RCC_PLLCmd(ENABLE);

    /* Wait till PLL is ready */
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }

    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08)
    {
    }
  }
  else
  { /* If HSE fails to start-up, the application will have wrong clock configuration.
       User can add here some code to deal with this error */    

    /* Go to infinite loop */
    while (1)
    {
    }



  }

  /* TIM2 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  /* GPIOC clock enable */
//  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);    

  /* Enable USART1, GPIOA, GPIOD and AFIO clocks */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 |
                         RCC_APB2Periph_GPIOA |
                         RCC_APB2Periph_GPIOB |
                         RCC_APB2Periph_AFIO, ENABLE);
  /* Enable USART2 clock */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
} 
/*******************************************************************************
* Function Name  : NVIC_Configuration
* Description    : Configures Vector Table base location.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void NVIC_Configuration(void)
{  
 NVIC_InitTypeDef NVIC_InitStructure;

#ifdef  VECT_TAB_RAM  
  /* Set the Vector Table base location at 0x20000000 */ 
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 
#else  /* VECT_TAB_FLASH  */
  /* Set the Vector Table base location at 0x08000000 */ 
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
#endif


  /* Enable the TIM2 gloabal Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

}

/**
  * @brief  Configures the different GPIO ports.
  * @param  None
  * @retval None
  */
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

#ifdef USE_STM3210C_EVAL
  /* Enable the USART3 Pins Software Remapping */
  GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, ENABLE);
  
  /* Enable the USART2 Pins Software Remapping */
  GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);  
#elif defined USE_STM3210B_EVAL
  /* Enable the USART2 Pins Software Remapping */
  GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
#endif

  /* Configure USARTy Rx as input floating */
  GPIO_InitStructure.GPIO_Pin = USARTy_RxPin;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(USARTy_GPIO, &GPIO_InitStructure);
  
  /* Configure USARTz Rx as input floating */
  GPIO_InitStructure.GPIO_Pin = USARTz_RxPin;
  GPIO_Init(USARTz_GPIO, &GPIO_InitStructure);  
  
  /* Configure USARTy Tx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Pin = USARTy_TxPin;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(USARTy_GPIO, &GPIO_InitStructure);

  /* Configure USARTz Tx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Pin = USARTz_TxPin;
  GPIO_Init(USARTz_GPIO, &GPIO_InitStructure); 
  
  /* Configure (PB.06) as output push-pull */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);  
  
    // Enable LEDs GPIO clock 
    if(LEDS_RCC_GPIO!=LCDBLEN_RCC_GPIO)
        RCC_APB2PeriphClockCmd(LEDS_RCC_GPIO, ENABLE);

    // Configure PE.00 and PE.01 as output push-pull 
    GPIO_InitStructure.GPIO_Pin =  LEDS_BOTH_PINS;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(LEDS_GPIO, &GPIO_InitStructure);  
  

   // Enable joystick GPIO clock 
    if( (JSTK_RCC_GPIO!=LCDBLEN_RCC_GPIO) && (JSTK_RCC_GPIO!=LEDS_RCC_GPIO) )
        RCC_APB2PeriphClockCmd(JSTK_RCC_GPIO, ENABLE);

    // Configure PE.03 to PE.06 as input 
    GPIO_InitStructure.GPIO_Pin = JSTK_ALL_PINS;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(JSTK_GPIO, &GPIO_InitStructure); 
}
/* USARTy and USARTz configuration ------------------------------------------------------*/
  /* USARTy and USARTz configured as follow:
        - BaudRate = 230400 baud  
        - Word Length = 8 Bits
        - One Stop Bit
        - No parity
        - Hardware flow control disabled (RTS and CTS signals)
        - Receive and transmit enabled
  */
void USART_Configuration(void)
{
  USART_InitStructure.USART_BaudRate = 115200;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  
  /* Configure USARTy */
  USART_Init(USARTy, &USART_InitStructure);
  /* Configure USARTz */
  USART_Init(USARTz, &USART_InitStructure);

  /* Enable USARTy DMA Rx and TX request */
  USART_DMACmd(USARTy, USART_DMAReq_Rx | USART_DMAReq_Tx, ENABLE);
  /* Enable USARTz DMA Rx and TX request */
  USART_DMACmd(USARTz, USART_DMAReq_Rx | USART_DMAReq_Tx, ENABLE);


  
  /* Enable the USARTy */
  USART_Cmd(USARTy, ENABLE);
  /* Enable the USARTz */
  USART_Cmd(USARTz, ENABLE);

}
/**
  * @brief  Configures the DMA.
  * @param  None
  * @retval None
  */
void DMA_Configuration(void)
{
  DMA_InitTypeDef DMA_InitStructure;

  /* USARTy TX DMA1 Channel (triggered by USARTy Tx event) Config */
  DMA_DeInit(USARTy_Tx_DMA_Channel); 
  DMA_InitStructure.DMA_PeripheralBaseAddr = USARTy_DR_Base;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer1;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_InitStructure.DMA_BufferSize = TxBufferSize1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(USARTy_Tx_DMA_Channel, &DMA_InitStructure);

  /* USARTy RX DMA1 Channel (triggered by USARTy Rx event) Config */
  DMA_DeInit(USARTy_Rx_DMA_Channel);  
  DMA_InitStructure.DMA_PeripheralBaseAddr = USARTy_DR_Base;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer1;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = TxBufferSize2;
  DMA_Init(USARTy_Rx_DMA_Channel, &DMA_InitStructure);
  
  /* USARTz TX DMA1 Channel (triggered by USARTz Tx event) Config */
  DMA_DeInit(USARTz_Tx_DMA_Channel);  
  DMA_InitStructure.DMA_PeripheralBaseAddr = USARTz_DR_Base;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer2;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_InitStructure.DMA_BufferSize = TxBufferSize2;  
  DMA_Init(USARTz_Tx_DMA_Channel, &DMA_InitStructure);
  
  /* USARTz RX DMA1 Channel (triggered by USARTz Rx event) Config */
  DMA_DeInit(USARTz_Rx_DMA_Channel);  
  DMA_InitStructure.DMA_PeripheralBaseAddr = USARTz_DR_Base;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer2;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = TxBufferSize1;
  DMA_Init(USARTz_Rx_DMA_Channel, &DMA_InitStructure);  
  
    /* Enable USARTy TX DMA1 Channel */
  DMA_Cmd(USARTy_Tx_DMA_Channel, ENABLE);
  /* Enable USARTy RX DMA1 Channel */
  DMA_Cmd(USARTy_Rx_DMA_Channel, ENABLE);

  /* Enable USARTz TX DMA1 Channel */
  DMA_Cmd(USARTz_Tx_DMA_Channel, ENABLE);
  /* Enable USARTz RX DMA1 Channel */
  DMA_Cmd(USARTz_Rx_DMA_Channel, ENABLE);
}
void TIM2_Configuration(void)
{
/* ---------------------------------------------------------------
    TIM2 Configuration: Output Compare Timing Mode:
    TIM2CLK = 36 MHz, Prescaler = 4, TIM2 counter clock = 7.2 MHz
    CC1 update rate = TIM2 counter clock / CCR1_Val = 146.48 Hz
    CC2 update rate = TIM2 counter clock / CCR2_Val = 219.7 Hz
    CC3 update rate = TIM2 counter clock / CCR3_Val = 439.4 Hz
    CC4 update rate = TIM2 counter clock / CCR4_Val =  878.9 Hz
  --------------------------------------------------------------- */
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;

  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 65535;
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  /* Prescaler configuration */
  TIM_PrescalerConfig(TIM2, 4, TIM_PSCReloadMode_Immediate);

  /* Output Compare Timing Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 

  TIM_OC1Init(TIM2, &TIM_OCInitStructure);
  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
  
  /* Output Compare Timing Mode configuration: Channel2 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR2_Val;

  TIM_OC2Init(TIM2, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);

  /* Output Compare Timing Mode configuration: Channel3 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR3_Val;

  TIM_OC3Init(TIM2, &TIM_OCInitStructure);

  TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);

  /* Output Compare Timing Mode configuration: Channel4 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR4_Val;

  TIM_OC4Init(TIM2, &TIM_OCInitStructure);

  TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);

  /* TIM IT enable */
  TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);

  /* TIM2 enable counter */
  TIM_Cmd(TIM2, ENABLE);

}

/**
  * @brief  Compares two buffers.
  * @param  pBuffer1, pBuffer2: buffers to be compared.
  * @param  BufferLength: buffer's length
  * @retval PASSED: pBuffer1 identical to pBuffer2
  *   FAILED: pBuffer1 differs from pBuffer2
  */
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
  while(BufferLength--)
  {
    if(*pBuffer1 != *pBuffer2)
    {
      return FAILED;
    }

    pBuffer1++;
    pBuffer2++;
  }

  return PASSED;
}

#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *   where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Langen Code bitte als Anhang!

Autor: Fun Rice (funnyrice)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, mach ich beim nächsten Mal.
Kann´s jetzt leider nicht mehr rückgängig machen.

MfG
FunRice

Autor: Heiko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab zwar noch nichts mit DMA gemacht, aber das hier klingt so, als 
müsste man es auch noch setzen...
    /* Enable USARTy TX DMA1 Channel */
  DMA_Cmd(USARTy_Tx_DMA_Channel, ENABLE);
  /* Enable USARTy RX DMA1 Channel */
  DMA_Cmd(USARTy_Rx_DMA_Channel, ENABLE);

  /* Enable USARTz TX DMA1 Channel */
  DMA_Cmd(USARTz_Tx_DMA_Channel, ENABLE);
  /* Enable USARTz RX DMA1 Channel */
  DMA_Cmd(USARTz_Rx_DMA_Channel, ENABLE);

MfG, Heiko

Autor: gsdfgsd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du initialisierst ja nur den DMA, du solltest auch den SW-Trigger setzen 
danach.

Geraten, ohne jetzt genau die FW-LIb oder den STM32 zu kennnen...

Autor: Fun Rice (funnyrice)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

genau da ist ja mein Verständnisproblem.

Beim Starten wird der String ja gesendet. aber wo/wie der Trigger 
gesetzt wird, verstehe ich nicht.

MfG
FunRice

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da der DMA-Kanal mit dem UART-Transmitter verbunden ist, ist ein 
Software-Trigger nicht erforderlich. Das DMA wird ausgelöst, wenn der 
Transmit-Puffer Platz hat. Wenn man den Transmitter nicht explizit 
abschaltet, dann ist das automatisch gegeben.

Allerdings reicht die Neu-Initialisierung des Kanals allein nicht aus, 
wie Heiko schon anmerkte. Er muss auch eingeschaltet werden. DMA_DeInit 
schaltet ihn aus und DMA_Init verhält sich dazu neutral - das halte ich 
übrigens für ziemlich zweifelhaft, denn wenn man diese Funktion bei 
eingeschaltetem DMA aufruft, dann riskiert man einen Amoklauf. Erst 
DMA_Cmd schaltet den Kanal wieder ein.

Freilich reicht es aus, an Stelle des elend langen DMA_DeInit vor dem 
erneuten DMA_Init einfach nur per DMA_Cmd den Kanal auszuschalten.

IMHO kommt man oft nicht darum herum, die Funktion der Hardware anhand 
der Referenz zu verstehen und für die Nutzung der FWlib deren Umsetzung 
auf die Hardware anhand des Quellcodes zu studieren.

Autor: Fun Rice (funnyrice)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> IMHO kommt man oft nicht darum herum, die Funktion der Hardware anhand
> der Referenz zu verstehen und für die Nutzung der FWlib deren Umsetzung
> auf die Hardware anhand des Quellcodes zu studieren.

Nun ja, das wäre die optimale Vorgehensweise.

Habe
        DMA_DeInit(USARTz_Tx_DMA_Channel);  
        DMA_InitStructure.DMA_PeripheralBaseAddr = USARTz_DR_Base;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer2;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
        DMA_InitStructure.DMA_BufferSize = TxBufferSize2;  
        DMA_Init(USARTz_Tx_DMA_Channel, &DMA_InitStructure)
durch
        DMA_Cmd(USARTz_Tx_DMA_Channel,SET); 
ersetzt.

Funktioniert leider noch immer nicht.
Ist ja unfassbar, was für ein Aufwand man betreiben muß, um mittels DMA 
zu senden.
Merkwürdig(für mich), daß es beim Starten einmalig funktioniert.

MfG
FunRice

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fun Rice schrieb:

> Funktioniert leider noch immer nicht.

Wundert mich nicht. Ein paar der DMA-Register ändern im Betrieb ihren 
Wert, nämlich der Zähler und die Speicheradresse. Wenn der Zähler mal 0 
ist, dann kannst du den Kanal einschalten so oft du willst.

Es läuft eher auf
        DMA_Cmd(USARTz_Tx_DMA_Channel,RESET); -- oder so ähnlich
        DMA_InitStructure.DMA_PeripheralBaseAddr = USARTz_DR_Base;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer2;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
        DMA_InitStructure.DMA_BufferSize = TxBufferSize2;
        DMA_Init(USARTz_Tx_DMA_Channel, &DMA_InitStructure)
        DMA_Cmd(USARTz_Tx_DMA_Channel,SET);
hinaus.

> Ist ja unfassbar, was für ein Aufwand man betreiben muß,
> um mittels DMA zu senden.

Der Aufwand an notwendiger Codierung ist recht gering (*), der Aufwand 
an Verständnis deutlich höher ;-).

*: Jedenfalls wenn man nur das tut, was die Hardware verlangt. Die kann 
nichts dafür, dass es mit der FWlib deutlich komplizierter aussieht. 
Eigentlich muss man nämlich nur: abschalten, Zähler+Adresse setzen, 
einschalten. Das sind 4 Programmzeilen.

Autor: Fun Rice (funnyrice)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm, ist der Adresszähler gemeint.

Folgendes bleibt dann auch wirkungslos:
          /* USARTz TX DMA1 Channel (triggered by USARTz Tx event) Config */
        DMA_DeInit(USARTz_Tx_DMA_Channel);  
        DMA_InitStructure.DMA_PeripheralBaseAddr = USARTz_DR_Base;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer2;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
        DMA_InitStructure.DMA_BufferSize = TxBufferSize2;  
        DMA_Init(USARTz_Tx_DMA_Channel, &DMA_InitStructure);
        
        DMA_Cmd(USARTz_Tx_DMA_Channel,SET);         

Vielleicht finde ich ja ein "begreifbares" Tutorial über STM32+DMA, wenn 
ich nicht über das Forum auf "´ne schnelle Lösung" komme.

MfG
FunRice

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nebenbei: USART-Empfang mit DMA ist nicht wirklich der einfachste Weg, 
DMA kennenzulernen. Weil du meistens nicht im Voraus weisst, wieviele 
Bytes demnächst noch eintrudeln werden, der DMA-Kanal aber genau das 
wissen will. Da kriegt man es dann mit dem circular mode, dem half 
transfer interrupt und möglicherweise auch timeouts zu tun, evtl. 
garniert mit race conditions. Senden ist ok, aber empfangen... (es gibt 
deshalb eine Appnote dazu).

Autor: Fun Rice (funnyrice)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab´s mir mit Hilfe der Beispielcodes "DMA_Polling" viel einfacher 
vorgestellt. Daraus geht aber nicht hervor, wie man mehr als ein Mal 
sendet. Ist echt für´n Popo.

MfG
FunRice

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe das mal ausprobiert. Funktioniert so wie es soll. Jede Sekunde 
ein "Hallo".

Der Code enthält ein paar Funktionen und Bitnamen aus meiner eigenen 
Umgebung, beispielsweise Zeug wie DMA_CCR_DIR_mem2per - aber hier geht 
es um die Demonstration des Prinzips, nicht um eine copy-and-paste 
Vorlage.
char hallo[] = "Hallo!\n";

int
main(void)
{
    rcc_clock();     // Taktinitialisierung
    systick_delay(); // Delay-Kalibrierung

    RCC->AHBENR  |= RCC_AHBENR_DMA1EN;
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;

    gpio_config(GPIOA, 1<<9, GPIO_Mode_Output2MHz | GPIO_AltOut_PushPull); // UART1 Tx
    usart_init(USART1, 9600, 8, USART_ParityNone);
    USART1->CR3 |= USART_CR3_DMAT;              // enable UART Tx DMA

    DMA1_Channel4->CCR = DMA_CCR_DIR_mem2per
                       | DMA_CCR_MINC
                       | DMA_CCR_PSIZE_8bits
                       | DMA_CCR_MSIZE_8bits
                       | DMA_CCR_PL_high;
    DMA1_Channel4->CPAR = (unsigned)&USART1->DR;

    printf("Run " __TIME__ "\n");
    while (1) {
        delay_ms(1000);

        DMA1_Channel4->CCR &= ~DMA_CCR_EN;      // disable DMA
        DMA1_Channel4->CMAR  = (unsigned)hallo;
        DMA1_Channel4->CNDTR = strlen(hallo);
        DMA1_Channel4->CCR |= DMA_CCR_EN;       // enable DMA
    }
}
Ich finde nicht, dass diese Form von DMA so kompliziert ist. Weniger 
geht ja nun wirklich nicht. Ist im Grunde nichts Anderes als das was du 
in der letzten hier beschriebenen Version machst, nur ohne FWlib.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du mal kontrolliert, ob es die richtige USART erwischt? Anfangs 
sendest du ja auf beiden USARTs, später aber nur auf einer.

Autor: Fun Rice (funnyrice)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, A. K.

vielen Dank für Deine Hilfe! Kann es leider erst heute Abend 
ausprobieren.

A. K. schrieb:
> Hast du mal kontrolliert, ob es die richtige USART erwischt? Anfangs
> sendest du ja auf beiden USARTs, später aber nur auf einer.

Ja, das sind noch Codezeilen aus dem Beispielprojekt die sich auf den 
USART1 beziehen. Ich teste aber erst mal den USART2 (USARTz). Der liegt 
auf dem extension-connector.
Wenn es dann mit USART2 inkl Empfang funktioniert, dann soll 
USART1,3,4 und evtl.5 dazukommen.

Mist, würde Deinen Code am liebsten sofort ausprobieren, geht jetzt aber 
leider nicht. Schätze erst ab 20:30 Uhr


MfG
FunRice

Autor: Fun Rice (funnyrice)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Juhu! Funktioniert!

Habe den Code angepasst und in die Funktion eingetragen.

Nun werde ich mich wohl erst Mal in die Empfangsgeschichte einarbeiten 
müssen.
Es ist in der Tat so, das die empfangenen Strings unterschiedlich lang 
sind. Ist ja unpraktisch, dass der DMA-Kanal "wissen" muss, wie lang der 
empfangene String sein soll. Und circular Mode sagt mir noch nichts.
Kann also nicht garantieren, daß keine Fregen zu Rx kommen ;-)

Danke nochmal A. K. für Dein Democode.


MfG
FunRice

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fun Rice schrieb:

> Es ist in der Tat so, das die empfangenen Strings unterschiedlich lang
> sind. Ist ja unpraktisch, dass der DMA-Kanal "wissen" muss, wie lang der
> empfangene String sein soll. Und circular Mode sagt mir noch nichts.

War etwas knapp und provokant formuliert, müssen tut er es nicht, es ist 
nur deutlich einfacher, wenn man es vorher weiss. Es ist eben nicht so 
einfach wie das Senden, weil man nicht einfach abwarten kann, bis das 
DMA durch ist, sondern meist schon vorher "live" in die DMA-Register 
spicken muss. Immerhin will man meist nicht abwarten bis der Puffer voll 
ist, bevor man das erste Byte davon in Angriff nimmt.

Ich habe grad mal in die AN3109 reingesehen. Naja. Mit der Timeout-Idee 
kann man vielleicht etwas anfangen, aber im Code zum DMA-FIFO fehlt m.E. 
genau der interessante Teil.

Autor: Fun Rice (funnyrice)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> aber im Code zum DMA-FIFO fehlt m.E.
> genau der interessante Teil.

Also, in der AN3109 ist kein Code, was sehr schade ist, weil ich z.Zt. 
nicht so tief in den Registern stecke, um es jetzt einbinden zu können.

MfG
FunRice

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dass es zu vielen Appnotes ein File mit Code und Projektkram gibt ist 
dir offenbar entgangen.

Allerdings ist nur die Initialisierung vom DMA-Controller drin, was der 
langweiligste Teil davon ist. Was ich dort nicht fand, ist der Teil, der 
daraus einen Bytestrom für die Anwendung macht.

Autor: Fun Rice (funnyrice)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ups, OK!

Kann es mir erst heute Abend ansehen.

MfG
FunRice

Autor: rohe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
prx schrieb:
> Dass es zu vielen Appnotes ein File mit Code und Projektkram gibt ist
> dir offenbar entgangen.

Hallo prx,
ich konnte auf www.st.com keinen Beispielcode zur AN3109 finden. Hast Du 
einen Link parat?
Danke und Gruss, Rohe

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.