//*****************************************************************************//*//* InitUART1 //* //* Initialize UART1.//* Default Settings: 9600,8,N,1//* //*****************************************************************************void InitUART1(uint8 BaudRate){ // assign port pins to UART functions MCF_GPIO_PUBPAR = 0 | MCF_GPIO_PUBPAR_TXD1_TXD1 | MCF_GPIO_PUBPAR_RXD1_RXD1; // Reset Receiver and Transmitter (UCR) MCF_UART1_UCR = MCF_UART_UCR_RESET_TX; MCF_UART1_UCR = MCF_UART_UCR_RESET_RX; // Reset Mode Pointer MCF_UART1_UCR = MCF_UART_UCR_RESET_MR; // Enable Interrupt Source (UIMR) // Transmit Interrupt will be enabled when que is not empty MCF_UART1_UIMR = 0 | MCF_UART_UIMR_RXRDY_FU; MCF_INTC0_IMRL &= ~(0 | MCF_INTC_IMRL_MASK14 | MCF_INTC_IMRL_MASKALL); MCF_INTC0_ICR14 = 0b00110110; // level 6, priority 6 // Initialize Input Enable Control (UACR) MCF_UART1_UACR = 0; // Select Receiver and Transmitter Clock (UCSR) MCF_UART1_UBG2 = (uint8)UART1_BAUDTABLE[5]; MCF_UART1_UBG1 = (uint8)(UART1_BAUDTABLE[5] >> 8); MCF_UART1_UCSR = 0 //Set Rx and Tx clocks to system clock | MCF_UART_UCSR_TCS(MCF_UART_UCSR_TCS_SYS_CLK) | MCF_UART_UCSR_RCS(MCF_UART_UCSR_TCS_SYS_CLK); // Set Mode Register 1 (UMR1) MCF_UART1_UMR = 0 // RX Ready will generate interrupt | MCF_UART_UMR_BC_8 // 8 bits/char | MCF_UART_UMR_PM_NONE; // no parity // Set Mode Register 2 (UMR2) MCF_UART1_UMR = 0 // normal mode | MCF_UART_UMR_SB_STOP_BITS_15; // stop bit width // Enable Transmitter and Receiver (UCR) MCF_UART1_UCR = 0 | MCF_UART_UCR_TX_ENABLED | MCF_UART_UCR_RX_ENABLED;}
//*****************************************************************************//*//* UART1 Interrupt Routine //* //* //*****************************************************************************__interrupt__void UART1Interrupt(void){uint8 temp; // Determine interrupt source if ((MCF_UART1_UISR & 4)) { temp = MCF_UART1_URB; MCF_UART1_UCR = MCF_UART_UCR_RESET_ERROR; MCF_UART1_UCR = MCF_UART_UCR_BKCHGINT; } if ((MCF_UART1_UISR & MCF_UART_UISR_TXRDY) == MCF_UART_UISR_TXRDY) { // Transmit Empty if (UART1_q_TX_size() == 0) { // nothing more to send, shutoff TX interrupt MCF_UART1_UIMR &= ~MCF_UART_UIMR_TXRDY; } else { // send the next byte MCF_UART1_UTB = pull_UART1_TX_q(); } } if((MCF_UART1_UISR & MCF_UART_UISR_RXRDY_FU) == MCF_UART_UISR_RXRDY_FU) { // Receive interrupt // put the received byte on the que // check error bit here if (MCF_UART1_USR & (0xF0)) { temp = MCF_UART1_URB; MCF_UART1_UCR = MCF_UART_UCR_RESET_ERROR; MCF_UART1_UCR = MCF_UART_UCR_BKCHGINT; } else { add_UART1_RX_q(MCF_UART1_URB); } }}
//*****************************************************************************//*//* UART1_getchar //* //* //*****************************************************************************uint16 UART1_getchar(void){uint16 RetVal; // set interrupt level to 7 mcf5xxx_wr_sr(0x2700); // disable RX interrupt MCF_UART1_UIMR &= ~MCF_UART_UIMR_RXRDY_FU; mcf5xxx_wr_sr(0x2000); if (UART1_q_RX_size() == 0) RetVal = QUE_EMPTY; // que is empty else { RetVal = UART1_RX_Q[UART1_RX_Q_TAIL]; if (++UART1_RX_Q_TAIL == UART1_Q_MAX) { UART1_RX_Q_TAIL = 0; } } mcf5xxx_wr_sr(0x2700); // Re-enable RX interrupt MCF_UART1_UIMR |= MCF_UART_UIMR_RXRDY_FU; mcf5xxx_wr_sr(0x2000); return(RetVal); }
Mark,
Thanks for the tips I will give it a try.
You mentioned keeping a copy of the mask register. Does the coldfire do a read-modify-write on this register?
Here is another strange thing that happens.
If I turn on both the transmitter and receiver in the initialization routine and write a 0 into the UIMR register, it still fires the interrupt because of the transmit ready bit. I don't understand why I still get the interrupt when all interrupt sources have been masked off.
Hi Jeff
The Mask register (UART block + 0x14) is writable to set and clear the mask bits.
When this address is read it doesn't return the mask bits which have been set but instead returns the Status of the interrupt bits. This means that a read and write are at the same location but the actual register accessed is different. This means that instructions like x |= y or x &+ ~y; will not work correctly.
I don't know why you are seeing an initial interrupt. I didn't hav ethis effect. Below I have copied the initialisation routine which I use - you should get the idea and maybe see something which could help explain the difference.
Regards
Mark
==========================================================
// User configuration
QUEUE_HANDLE SerialPortID;
TTYTABLE tInterfaceParameters; // table for passing information to driver
tInterfaceParameters.ucChannel = 1; // use serial channel 1 on evaluation board / target
tInterfaceParameters.ucSpeed = temp_pars->temp_parameters.ucSerialSpeed; // baud rate
tInterfaceParameters.Rx_tx_sizes.RxQueueSize = RX_BUFFER_SIZE; // input buffer size
tInterfaceParameters.Rx_tx_sizes.TxQueueSize = TX_BUFFER_SIZE; // output buffer size
tInterfaceParameters.cTask_to_wake = OWN_TASK; // wake self when messages have been received
tInterfaceParameters.ucFlowHighWater = temp_pars->temp_parameters.ucFlowHigh;// set the flow control high and low water levels in %
tInterfaceParameters.ucFlowLowWater = temp_pars->temp_parameters.ucFlowLow;
tInterfaceParameters.usConfig = temp_pars->temp_parameters.usSerialMode;
SerialPortID = fnOpen( TYPE_TTY, FOR_I_O, &tInterfaceParameters ); // open or change the channel with defined configurations
... the following is called somewhere down the line
// configure the SCI hardware
//
void fnConfigSCI(unsigned char ucChannel, TTYTABLE *pars)
{
unsigned char *ucReg = fnSelectChannel(ucChannel); // set register pointer to corresponding block (command register)
unsigned short usSpeed;
unsigned char ucBits = UART_8_BIT;
switch (ucChannel) { // First configure the GPIO pins for UART use
case 0:
PUAPAR |= 0x05; // Set TX/RX on UA
IC_ICR_0_13 = (INTERRUPT_LEVEL_5 | INTERRUPT_PRIORITY_1); // define interrupts level and priority
IC_IMRL_0 &= ~(UART0_PIF_INT_L | MASK_ALL_INT); // unmask interrupt source
break;
case 1:
PUBPAR |= 0x05; // Set TX/RX on UB
IC_ICR_0_14 = (INTERRUPT_LEVEL_5 | INTERRUPT_PRIORITY_2); // define interrupts level and priority
IC_IMRL_0 &= ~(UART1_PIF_INT_L | MASK_ALL_INT); // unmask interrupt source
break;
case 2:
PUCPAR |= 0x03; // Set TX/RX on UB
IC_ICR_0_15 = (INTERRUPT_LEVEL_5 | INTERRUPT_PRIORITY_3); // define interrupts level and priority
IC_IMRL_0 &= ~(UART2_PIF_INT_L | MASK_ALL_INT); // unmask interrupt source
break;
default:
return; // Invalid UART channel
}
*ucReg = UART_RESET_RX; // reset rx and tx and ensure internal command pointer at start
*ucReg = UART_RESET_TX;
*ucReg = UART_RESET_CMD_PTR;
ucReg -= (UCR_0_OFFSET - USR_UCSR_0_OFFSET); // set to clock select register
*ucReg = (UART_RX_BUS_CLK | UART_TX_BUS_CLK); // Use internal bus clock
ucReg += (UBG1_0_OFFSET - USR_UCSR_0_OFFSET); // Move to BRG register
switch (pars->ucSpeed) {
case SERIAL_BAUD_300:
usSpeed = BUS_CLOCK/300/32; // set 300
break;
case SERIAL_BAUD_600:
usSpeed = BUS_CLOCK/600/32; // set 600
break;
case SERIAL_BAUD_1200:
usSpeed = BUS_CLOCK/1200/32; // set 1200
break;
case SERIAL_BAUD_2400:
usSpeed = BUS_CLOCK/2400/32; // set 2400
break;
case SERIAL_BAUD_4800:
usSpeed = BUS_CLOCK/4800/32; // set 4800
break;
case SERIAL_BAUD_9600:
usSpeed = BUS_CLOCK/9600/32; // set 9600
break;
case SERIAL_BAUD_14400:
usSpeed = BUS_CLOCK/14400/32; // set 14400
break;
default: // if not valid value set this one
case SERIAL_BAUD_19200:
usSpeed = BUS_CLOCK/19200/32; // set 19200
break;
case SERIAL_BAUD_38400:
usSpeed = BUS_CLOCK/38400/32; // set 38400
break;
case SERIAL_BAUD_57600:
usSpeed = BUS_CLOCK/57600/32; // set 57600
break;
case SERIAL_BAUD_115200:
usSpeed = BUS_CLOCK/115200/32; // set 115200
break;
case SERIAL_BAUD_230400:
usSpeed = BUS_CLOCK/230400/32; // set 230400
break;
}
*ucReg = (unsigned char)(usSpeed >> 8);
ucReg += (UBG2_0_OFFSET - UBG1_0_OFFSET);
*ucReg = (unsigned char)(usSpeed); // Baud rate set
ucReg -= (UBG2_0_OFFSET - UMR1_2_0_OFFSET); // set to Mode register
if (pars->usConfig & CHAR_7) {
ucBits = UART_7_BIT;
}
if (pars->usConfig & (RS232_ODD_PARITY | RS232_EVEN_PARITY)) {
if (pars->usConfig & RS232_ODD_PARITY) {
*ucReg = (UART_WITH_PARITY | ucBits | ODD_PARITY); // 7/8 bits - odd parity
}
else {
*ucReg = (UART_NO_PARITY | ucBits); // 7/8 bits - even parity
}
}
else {
*ucReg = (ucBits); // 7/8 bits - no parity
}
if (pars->usConfig & TWO_STOPS) { // The mode register 2 has been selected by previous write
*ucReg = UART_TWO_STOP;
}
else if (pars->usConfig & ONE_HALF_STOPS) {
*ucReg = UART_ONE_HALF_STOP;
}
else {
*ucReg = UART_ONE_STOP;
}
// Enable receiver (tx enabled when used)
ucReg = fnSelectChannel(ucChannel); // set register pointer to corresponding block (command register)
*ucReg = UART_RX_ENABLE; // enable RX interrupt and Rx
ucReg += (UIMR_UISR_0_OFFSET - UCR_0_OFFSET);
ucEnabledState[ucChannel] |= UART_RXRDY_MASK; // we must make a backup since the register can not be read
*ucReg = ucEnabledState[ucChannel];
}
=====================================================================
Mark,
Thanks for taking time to look at my problem.
Could you explain more what you mean in item 1?
Thanks,
Jeff
Hi Jeff
I have implemented a UART driver for the three UARTs in the M5223X for the uTasker operating system with integrated TCP/IP stack - see the following posing:
http://forums.freescale.com/freescale/board/message?board.id=CFCOMM&message.id=274
The uTasker also simulates the UARTs on a PC and is available free for non-commercial work.
It is too late to check your code in detail tonight but a couple of first thoughts:
1. It is generally best to put the interrupts in a while loop to avoid quitting when a new interrupt arrives.
2. I found it best (easiest) to always disable the transmitter when it is not in use since it otherwise causes an empty interrupt always to be signalled and this is difficult to distinguish in the general rx/tx interrupt routine. I think that you have also done this
3. It is probably best to read MCF_UART1_UISR only once during a while loop in the interrupt routine. Store it temporarily in a variable and check the flags from the variable and not each time from the register since this may be resetting the opposite interrupt flag (which is probably happening in your case).
I have a driver with RTS/CTS, XON-XOFF/escape sequening/scan sequence support. All code is available with a simple educational license agreement (or for evaluation purposes). If it could help please contact me directly. I think that point 3 will in fact solve your present problem but tell me if it doesn't and I will look in more detail.
Regards
Mark Butcher
www.mjbc.ch
I forgot to mention that if I disable the transmitter none of this happens.