組み込み技術を向上したい!!

でも組み込み以外にも手を出し始めました・・・

STM32F429I-DISCOとUARTとDMA

UARTを使ってみる。
開発環境はいつものCooCoxのやつ。

PC12をUART5 TX
PD2をUART5 RX

に割り当てて、動作を確認。 せっかくなのでDMA使ってみる。 以下ソースなど。

/* とりあえずRX用のバッファを作る。(ポインタの方が良さげだけど) */
typedef struct {
  char rx_buffer[UART5_RX_BUFF_MAX]; // RX buffer
  uint16_t w_posi;             //
  uint16_t r_posi;             //
  uint16_t len;
}UART_RX_t;

static UART_RX_t sUart5_RX_buff;

/* TX用のバッファ。DMAと関連付ける */
static char	sUart5_TX_buff[UART5_TX_BUFF_MAX];
static DMA_InitTypeDef  DMA_InitStructUART5TX;

/*! *******************************************************************
 *	@note 	stream7は使えたけど、
			1, 4, 5はダメだった・・・。
			正確な理由を知りたいなぁ・・・。
 **********************************************************************/
void Uart5_TX_DMA(char* data, uint16_t len)
{
	if ( len < UART5_TX_BUFF_MAX ) {
		memcpy(sUart5_TX_buff, data, len);
		DMA_InitStructUART5TX.DMA_BufferSize = len;
		DMA_Init(DMA1_Stream7, &DMA_InitStructUART5TX);
		DMA_Cmd(DMA1_Stream7, ENABLE);
	}
}
/*! *******************************************************************
 *
 **********************************************************************/
UART_RX_t* Uart5_GetRxData(void)
{
	return (&sUart5_RX_buff);
}
/*! *******************************************************************
 *
 **********************************************************************/
void UartInit(void)
{
	sUart5_RX_buff.r_posi = 0;
	sUart5_RX_buff.w_posi = 0;
	sUart5_RX_buff.len = 0;

	uart_clock_init();
	uart_gpio_init();
	uart_peri_init();
	uart_dma_init();
	UartNvicInit();		// すぐに使わない場合はこいつは後回しでOK
}
/*! *******************************************************************
 *	クロック関係初期化 
    ※DMA使いたいので、それもまとめて記載
 **********************************************************************/
static void uart_clock_init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
}
/*! *******************************************************************
 *	GPIO 初期化
 **********************************************************************/
static void uart_gpio_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/* TX */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	/* Connect USART pins to AF */
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);

	/* RX */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);
}
/*! *******************************************************************
 *	ペリフェラルの初期化
 **********************************************************************/
static void uart_peri_init(void)
{
	/* 	- BaudRate = 115200 baud
		- Word Length = 8 Bits
		- One Stop Bit
		- No parity
		- Hardware flow control disabled (RTS and CTS signals)
		- Receive and transmit enabled	*/
	USART_InitTypeDef USART_InitStructure;

	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;

	USART_Init(UART5, &USART_InitStructure);
	USART_Cmd(UART5, ENABLE);

	/* RX-Interrupt enable */
	USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);
}
/*! *******************************************************************
 *	DMAの初期化。 RXは固定電文長で使わない予定なので、DMA使わない
 **********************************************************************/
static void uart_dma_init(void)
{
	DMA_InitStructUART5TX.DMA_Channel = DMA_Channel_4;
	DMA_InitStructUART5TX.DMA_PeripheralBaseAddr = (uint32_t)&UART5->DR;
	DMA_InitStructUART5TX.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructUART5TX.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructUART5TX.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructUART5TX.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
//	DMA_InitStructUART5TX.DMA_Mode = DMA_Mode_Circular;	// ずーとTXループさせたいならこっち
	DMA_InitStructUART5TX.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructUART5TX.DMA_Priority = DMA_Priority_High;
	DMA_InitStructUART5TX.DMA_FIFOMode = DMA_FIFOMode_Enable;
	DMA_InitStructUART5TX.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
	DMA_InitStructUART5TX.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	DMA_InitStructUART5TX.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

	/***********************************************************************************
	 *	for TX
	 ***********************************************************************************/
	DMA_DeInit(DMA1_Stream7);
	DMA_InitStructUART5TX.DMA_DIR = DMA_DIR_MemoryToPeripheral; // Transmit
	DMA_InitStructUART5TX.DMA_Memory0BaseAddr = (uint32_t)sUart5_TX_buff;
	DMA_InitStructUART5TX.DMA_BufferSize = 0;
	DMA_Init(DMA1_Stream7, &DMA_InitStructUART5TX);
	/* Enable the USART Tx DMA request */
	USART_DMACmd(UART5, USART_DMAReq_Tx, ENABLE);
	/* Enable DMA Stream Half Transfer and Transfer Complete interrupt */
	DMA_ITConfig(DMA1_Stream7, DMA_IT_TC | DMA_IT_HT , ENABLE);
	/* Enable the DMA TX Stream */
	DMA_Cmd(DMA1_Stream7, DISABLE);
}
/*! *******************************************************************
 * 割り込み設定
 **********************************************************************/
void UartNvicInit(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	/* Configure the Priority Group to 2 bits */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

	/******************************************************************************
	 * for TX
	 ******************************************************************************/
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream7_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	/* enable UART Interrupt-Vector */
	NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	sUart5_RX_buff.r_posi = 0;
	sUart5_RX_buff.w_posi = 0;
	sUart5_RX_buff.len = 0;
}
/*! *******************************************************************
 * 割り込み解除
 **********************************************************************/
void UartNvicDeInit(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	/* Configure the Priority Group to 2 bits */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

	/******************************************************************************
	 * for TX
	 ******************************************************************************/
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream7_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
	NVIC_Init(&NVIC_InitStructure);

	/* enable UART Interrupt-Vector */
	NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
	NVIC_Init(&NVIC_InitStructure);
}
/*! *******************************************************************
 *	@note	TX DMA
 **********************************************************************/
void DMA1_Stream7_IRQHandler(void)
{
  /* Test on DMA Stream Transfer Complete interrupt */
  if (DMA_GetITStatus(DMA1_Stream7, DMA_IT_TCIF7))
  {
    /* Clear DMA Stream Transfer Complete interrupt pending bit */
    DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_TCIF7);
    DMA_Cmd(DMA1_Stream7, DISABLE);
  }

  /* Test on DMA Stream Half Transfer interrupt */
  if (DMA_GetITStatus(DMA1_Stream7, DMA_IT_HTIF7))
  {
    /* Clear DMA Stream Half Transfer interrupt pending bit */
    DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_HTIF7);
  }
}

/*! *******************************************************************
 *	@note	RX UART IRQ
 **********************************************************************/
void UART5_IRQHandler(void)
{
	if (USART_GetITStatus(UART5, USART_IT_RXNE) == SET) {
		sUart5_RX_buff.rx_buffer[sUart5_RX_buff.w_posi] = USART_ReceiveData(UART5);
		sUart5_RX_buff.w_posi++;
		if ( sUart5_RX_buff.w_posi == UART5_RX_BUFF_MAX ) {
			sUart5_RX_buff.w_posi = 0;
		}
		sUart5_RX_buff.len++;
	}
}

感想:受信もテスト的にDMA試したけどうまくいかんかった。
ペリフェラルに対応したDMAのチャンネルとストリームがあるみたいだけど、
ネット上で正確な情報を見つけきらんかった。

とりあえずemWin使って、RX内容をMULTIEDITに表示させてみたりしたけど、
何かハイテクだった。
オーバーフローしないようにいちいちMULTIEDIT_GetTextSize()して
MULTIEDIT_SetCursorOffset()して
MULTIEDIT_GetText()して
MULTIEDIT_AddKey()でGUI_KEY_DELETEでデリートするのが面倒だったけど、
自分で作るよりemWinとか使った方がかなり簡単で良いものができると思った。

簡単なUARTの動作確認としては使えそう。