STM32F411をHALを使わずにUART送信

#Indroduction
STM32F4のUSART6を使って、UART通信を行うためのBSWを作った。
HALを使ったサンプルはいっぱい転がっているが、趣味であるならばベアメタルなやり方も悪くはない。

#目的
アプリ側が任意のタイミングでコールすることバッファに蓄積されたデータをDMA経由でUSART6に転送しUART送信する機能を提供する。
最終的な形はアプリ側が5msec周期くらいでコールして周期送信させたい。

アプリコール関数 
uart6_send();
これをコールすることでリングバッファから送信用バッファにデータをコピーしてDMAに投げ込む（送信開始）

#前提条件
マイコンボード Nucleo-F411RE
クロック設定   APB2:80MHz
開発環境      CrossWorks for ARM

#ポイント
＜考え方＞
アプローチとしては2つやり方があると思う。
1 DMAをサーキュラモードにして、固定のバッファの中身を送り続ける。
　→「いつも同じ長さ」のメッセージでいいなら多分これが一番楽。
2 任意タイミングで送信用の関数をコールしたときに、DMAに送信長をセットしてUSARTを起動する。
　→DMA送信完了割り込みでDMAを禁止→USARTの送信完了でUSARTを止める。
　　→今回は送信長は可変にしたいので、今回はこっちを使った。

＜ボーレートの設定＞
昔のH8とかのクセが抜けない悪癖で若干悩んだ.
どーもSTM32と言うマイコンはUSARTのボーレートジェネレータは小数点以下もイケるらしい。
この部分。
USART6->BRR |= (43<<4) + 7;             //baudrate is 115.2kbps(APB2 80MHz)

（43<<4）が整数部
+ 7が小数部。
要はこのレジスタの下位4bitは固定小数として扱える。
これのおかげでボーレートジェネレータの誤差は0.1%以下に簡単に追い込める。
速度を上げていってもデータが化けることがない。
便利になったもんだ。

#コード
```c:uart.h
#ifndef	UART6
#define UART6

extern void uart6_init(void);
extern void uart6_send(void);
#endif
```
```c:uart.c
#include "stm32f4xx.h"
#include "uart6.h"
#include "var.h"
#include "cont.h"
#include "typedef.h"

static char TX_BUFF[UART_BUFF_SIZE];		    //Temp Buffer for TX

void uart6_init(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_USART6EN;	    //USART clk start(80MHz)
    
    DMA2_Stream7 -> CR |=  DMA_SxCR_CHSEL_0;	    //DMA2 Stream7 is USART6_TX
    DMA2_Stream7 -> CR &= ~DMA_SxCR_CHSEL_1;
    DMA2_Stream7 -> CR |=  DMA_SxCR_CHSEL_2;
    DMA2_Stream7 -> NDTR = 0;
    DMA2_Stream7 -> PAR = (uint32)&(USART6->DR);    //peripheral register is USART6_DR
    DMA2_Stream7 -> M0AR = (uint32)&TX_BUFF;	    //Memory address set
    
    DMA2_Stream7 -> CR |=  DMA_SxCR_DIR_0;	    //DMA2 Stream7 Memory to Peripheral
    DMA2_Stream7 -> CR &= ~DMA_SxCR_DIR_1;
    DMA2_Stream7 -> CR &= ~DMA_SxCR_CIRC;	    //Circular Mode is Disable
    
    DMA2_Stream7 -> CR &= ~DMA_SxCR_PSIZE_0;	    //Peripheral Data Size is 8byte
    DMA2_Stream7 -> CR &= ~DMA_SxCR_PSIZE_1;
    DMA2_Stream7 -> CR &= ~DMA_SxCR_PINC;	    //Peripheral address Pointer is fixed
    
    DMA2_Stream7 -> CR &= ~DMA_SxCR_MSIZE_0;	    //Memory Data Size is 8byte
    DMA2_Stream7 -> CR &= ~DMA_SxCR_MSIZE_1;
    DMA2_Stream7 -> CR |=  DMA_SxCR_MINC;	    //Memory address Pointer is incremented
    
    DMA2_Stream7 -> CR |=  DMA_SxCR_TCIE;	    //DMA Transfer complete interrupt is enable
    DMA2_Stream7 -> CR &= ~DMA_SxCR_PFCTRL;	    //DMA is the flow Controller

    USART6->CR2 &= ~USART_CR2_STOP_0;		    //USART stop bits = 1
    USART6->CR2 &= ~USART_CR2_STOP_1;

    USART6->CR1 &= ~USART_CR1_OVER8;		    //USART oversampling by 16
    USART6->CR1 &= ~USART_CR1_M;		    //Startbit 1, Databits 8, Stopbit n,
    USART6->CR1 &= ~USART_CR1_PCE;		    //Parity control is disabled

    USART6->BRR |= (43<<4) + 7;			    //baudrate is 115.2kbps(APB2 80MHz)
    USART6->CR3 |=  USART_CR3_DMAT;		    //USART DMA transmit enable 
    USART6->CR1 |=  USART_CR1_UE;		    //USART is enable
    USART6->CR1 |=  USART_CR1_RE;		    //USART receiver is enable
    USART6->CR1 |=  USART_CR1_TCIE;		    //Interrupt -> Transmit Complete
    
    NVIC_SetPriority(USART6_IRQn,9);		    //USART6 Interrupt Priority is 9
    NVIC_EnableIRQ(USART6_IRQn);
    NVIC_SetPriority(DMA2_Stream7_IRQn,10);	    //Interrupt Priority is 10
    NVIC_EnableIRQ(DMA2_Stream7_IRQn);
}

void DMA2_Stream7_IRQHandler(void)
{
    if((DMA2->HISR & DMA_HISR_TCIF7)==DMA_HISR_TCIF7)
    {
	DMA2_Stream7 -> CR &= ~DMA_SxCR_EN;	    //DMA is Disable
	DMA2->HIFCR |= DMA_HIFCR_CTCIF7;	    //Interrupt Flag is Clear
    }
}

void USART6_IRQHandler(void)
{
    if(USART6->SR & USART_SR_TC)
    {
	USART6->CR1 &=  ~USART_CR1_TE;		    //USART transmitter is Disable
	USART6->SR &= ~USART_SR_TC;		    //Interrupt Flag is Clear
    }
}

void uart6_send(void)
{
    int8 length;
    length = ring_buf_deq(&mTX_WORK,TX_BUFF);	    //From Work memory -> Send memory
    
    //Data is available?
    if(length >= 1)
    {
	DMA2_Stream7 -> NDTR = length;		    //Set Transmit length
	DMA2_Stream7 -> CR |=  DMA_SxCR_EN;	    //DMA is Enable
	USART6->CR1 |=  USART_CR1_TE;		    //USART transmitter is Enable
    }
}
```