-
Although in PCs, serial ports are gradually disappearing, in the embedded field, serial ports can still be said to be popular because they are low-cost and convenient to program. On systems without display screens or input devices, serial ports are even more popular. Indispensable, together with HyperTerminal, it solves the problem of information display and input.
After several days of hard work, the NativeSample transplantation work of .Net Micro Framework on the Cortex-M3 platform is about to reach a stage. At present, the startup code, SRAM, clock (RCC), interrupt (NVIC), SysTick, GPIO, Serial port, NandFlash (FMSC) and other related functions, these codes can be said to be the minimum set to make TinyClr work normally. With these work as a foundation, the next step can be to transplant TinyClr. If the Cortex-M3 development board we use has more than 2M RAM, then our work may be 90% completed at this point, but due to limited resources, the next step of debugging must be the Flash version, so there will be a lot of unknown work, and debugging will also become difficult. No matter how we The journey of .Net Micro Framework PortingKit will continue. However, to be honest, completing these tasks from scratch is difficult but rewarding. My understanding of ARM development (especially Cortex-M3) has improved to a new level. level.
Okay, let's talk about the development of serial port driver.
Like GPIO development, we still need to write serial port-related register code in CortexM3.h.
struct CortexM3_Usart
{
static const UINT32 c_MAX_BAUDRATE = 45000000;
static const UINT32 c_MIN_BAUDRATE = 1200;
static const UINT32 c_Base1 = 0x40013800;
static const UINT32 c_Base2 = 0x40004400;
static const UINT32 c_Base3 = 0x40004800;
/****/ volatile UINT16 SR;
static const UINT16 SR_TXE=((UINT16)0x0080);
static const UINT16 SR_TC=((UINT16)0x0040);
static const UINT16 SR_RXNE=((UINT16)0x0020);
UINT16 RESERVED0;
/****/ volatile UINT16 DR;
UINT16 RESERVED1;
/****/ volatile UINT16 BRR;
UINT16 RESERVED2;
/****/ volatile UINT16 CR1;
static const UINT16 CR1_UE_Set = ((UINT16)0x2000); //USART Enable Mask
static const UINT16 CR1_UE_Reset = ((UINT16)0xDFFF); //USART Disable Mask
static const UINT16 CR1_Parity_No = ((UINT16)0x0000);
static const UINT16 CR1_Parity_Even = ((UINT16)0x0400);
static const UINT16 CR1_Parity_Odd = ((UINT16)0x0600);
static const UINT16 CR1_DataBit_8 = ((UINT16)0x0000);
static const UINT16 CR1_DataBit_9 = ((UINT16)0x1000);
static const UINT16 CR1_Mode_Rx = ((UINT16)0x0004);
static const UINT16 CR1_Mode_Tx = ((UINT16)0x0008);
static const UINT16 CR1_CLEAR_Mask = ((UINT16)0xE9F3);
static const UINT16 CR1_PEIE = ((UINT16)0x0100);
static const UINT16 CR1_TXEIE = ((UINT16)0x0080);
static const UINT16 CR1_TCIE = ((UINT16)0x0040);
static const UINT16 CR1_RXNEIE = ((UINT16)0x0020);
UINT16 RESERVED3;
/****/ volatile UINT16 CR2;
static const UINT16 CR2_StopBits_1 = ((UINT16)0x0000);
static const UINT16 CR2_StopBits_0_5 = ((UINT16)0x1000);
static const UINT16 CR2_StopBits_2 = ((UINT16)0x2000);
static const UINT16 CR2_StopBits_1_5 = ((UINT16)0x3000);
static const UINT16 CR2_StopBits_Mask= ((UINT16)0xCFFF); /* USART CR2 STOP Bits Mask */
UINT16 RESERVED4;
/****/ volatile UINT16 CR3;
static const UINT16 CR3_HardwareFlowControl_None = ((UINT16)0x0000);
static const UINT16 CR3_HardwareFlowControl_RTS = ((UINT16)0x0100);
static const UINT16 CR3_HardwareFlowControl_CTS = ((UINT16)0x0200);
static const UINT16 CR3_HardwareFlowControl_RTS_CTS = ((UINT16)0x0300);
static const UINT16 CR3_HardwareFlowControl_Mask = ((UINT16)0xFCFF);
UINT16 RESERVED5;
/****/ volatile UINT16 GTPR;
UINT16 RESERVED6;
};
With the above code, we can easily operate the serial port register.
The initialization of the serial port requires the following initialization work (the STM3210E development board has three serial ports, we will take serial port 1 as an example):
1. Turn on the serial port clock
UsartId = CortexM3_NVIC::c_IRQ_Index_USART1;
RCC.APB2ENR |= CortexM3_RCC::APB2_GPIOA | CortexM3_RCC::APB2_USART1;
2. Activation interrupt
if(!CPU_INTC_ActivateInterruptEx( UsartId, (UINT32)(void *)USART1_IRQHandler)) return FALSE;
3. Set serial port parameters, such as baud rate, parity, data bits, stop bits, etc.
slightly
4. GPIO redefinition
CPU_GPIO_DisablePin(GPIO_Driver::PA9,RESISTOR_DISABLED,FALSE,GPIO_ALT_MODE_1);
CPU_GPIO_DisablePin(GPIO_Driver::PA10,RESISTOR_DISABLED,TRUE,GPIO_ALT_MODE_2);
5. Serial port enablement
Usart.CR1 |= CortexM3_Usart::CR1_UE_Set;
Complete the sending and receiving of data in the interrupt function:
void CortexM3_USART_Driver::ISR( void* param )
{
UINT32 comPort = (UINT32)param;
CortexM3_Usart &Usart=CortexM3::Usart(comPort);
char c;
UINT32 Status;
Status = Usart.SR;
if(Status & CortexM3_Usart::SR_RXNE)
{
c = Usart.DR;
USART_AddCharToRxBuffer( comPort, c );
Events_Set( SYSTEM_EVENT_FLAG_COM_IN );
}
if(Status & CortexM3_Usart::SR_TC)
{
if(0 == (c_RefFlagTx & g_CortexM3_USART_Driver.m_RefFlags[comPort]))
{
return;
}
if(USART_RemoveCharFromTxBuffer( comPort, c ))
{
WriteCharToTxBuffer( comPort, c );
}
else
{
// disable further Tx interrupts since we are level triggered
TxBufferEmptyInterruptEnable(comPort, FALSE);
}
Events_Set( SYSTEM_EVENT_FLAG_COM_OUT );
}
}
The core code is the relevant content introduced above. Below we write a serial port test code in NativeSample:
void ApplicationEntryPoint()
{
while(TRUE)
{
if(Events_WaitForEvents(SYSTEM_EVENT_FLAG_COM_IN,100))
{
Events_Clear(SYSTEM_EVENT_FLAG_COM_IN);
char bytData[512];
int Size=USART_BytesInBuffer(0,TRUE);
USART_Read(0,bytData,Size);
for(int i=0;i<Size;i++)
debug_printf("%c",bytData[i]);
}
debug_printf("Hello Micro Framework!!!rn");
}
}