MCF5407 UART interrupt masks seem inverted

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MCF5407 UART interrupt masks seem inverted

1,501 Views
jbolduc
Contributor I

Hi, I am having a lot of trouble configuring the UART on the MCF5407. The only way I was able to make the UART work with the interrupt is to inverse the UIMR bit logic; the datasheet says that we must set TxRDY and FFULL so the interrupts can be asserted but for me, it's the opposite.

I must clear FFULL for Rx, and clear TxRDY when sending and set when software tx fifo is empty.

I copied the problematic code below. To make it work for me, I must inverse ENABLE and DISABLE in the main loop and in HandleUart(void).

When I try to transfer this code to the main project, we have interrupt issues. There is something wrong that I can't figure out.

Thanks for the help

#include "mcf5407.h"
#include "CpuReg.h"
#include "FifoBuffer.hpp"

#define ENABLE TRUE
#define DISABLE FALSE

#define CPU_CLOCK_FREQ_HZ 54000000 // 54 MHz for NGDU

#define VECTOR_TABLE 0x00000000

#define UART0_ICR MCF5407_SIM_ICR4

void Hardware_Init();
void SetSR( UINT32 sr );
UINT32 GetSR();

static unsigned char g_rxBuffer[256];
static FifoBuffer<unsigned char> g_rxFifo(g_rxBuffer, 256);

static unsigned char g_txBuffer[256];
static FifoBuffer<unsigned char> g_txFifo(g_txBuffer, 256);

typedef enum
{
 SERIAL_CMD_NONE = 0x00, // no command - ignored
 SERIAL_CMD_RESET_MRP = 0x01, // reset mode register pointer
 SERIAL_CMD_RX_RESET = 0x02, // reset the receiver
 SERIAL_CMD_TX_RESET = 0x03, // reset the transmitter
 SERIAL_CMD_RST_ERR_STAT = 0x04, // reset the receiver
 SERIAL_CMD_RESET_BCI = 0x05, // reset break change interrupt
 SERIAL_CMD_START_BREAK = 0x06, // start a break
 SERIAL_CMD_STOP_BREAK = 0x07 // stop break
} SERIAL_CMD;

void SendCommand(SERIAL_CMD enCmd)
{
 uint8 cmd = ((UINT8)enCmd & 0x07)<<4;
 CPU_WR(MCF5407_UART0_UCR, cmd);
}

void SetBaudrate()
{
 UINT16 divisor = ROUND32(CPU_CLOCK_FREQ_HZ / 32.0f / 19200 ); // SERIAL_19K2_BAUD

 CPU_WR(MCF5407_UART0_UCSR, 0xDD); // Use prescaled CLKIN for tx/rx
 CPU_WR(MCF5407_UART0_UBG2, (UINT8)divisor); // Lower byte of divisor
 CPU_WR(MCF5407_UART0_UBG1, (UINT8)(divisor >> 8)); // Upper byte of the divisor
}

void Transmitter(BOOL bEnable)
{
 UINT8 bitCode = bEnable ? (0x01 << 2) : (0x02 << 2);
 CPU_WR(MCF5407_UART0_UCR, bitCode);
}

void Receiver(BOOL bEnable)
{
 UINT8 bitCode = bEnable ? 0x01 : 0x02;
 CPU_WR(MCF5407_UART0_UCR, bitCode);
}

void ReceiverInterrupts(BOOL bEnable)
{
 volatile UINT8 status = CPU_RD(MCF5407_UART0_UIMR);
 if (bEnable) {
 status |= MCF5407_UART_UIMR_FFULL; // Enable
 } else {
 status &= ~MCF5407_UART_UIMR_FFULL; // Disable
 }
 CPU_WR(MCF5407_UART0_UIMR, status);
}

void TransmitterInterrupts(BOOL bEnable)
{
 volatile UINT8 status = CPU_RD(MCF5407_UART0_UIMR);
 if (bEnable) {
 status |= MCF5407_UART_UIMR_TXRDY; // Enable
 } else {
 status &= ~MCF5407_UART_UIMR_TXRDY; // Disable
 }

 CPU_WR(MCF5407_UART0_UIMR, status);
}

void SetInterruptMask(BOOL bSet)
{
 UINT32 mask = CPU_RD32(MCF5407_SIM_IMR);
 if (bSet) {
 mask |= MCF5407_SIM_IMR_UART0;
 } else {
 mask &= ~MCF5407_SIM_IMR_UART0;
 }
 CPU_WR32(MCF5407_SIM_IMR, mask);
}

#define ANY_UART_ERRORS (MCF5407_UART_USR_RB | \
 MCF5407_UART_USR_FE | \
 MCF5407_UART_USR_PE | \
 MCF5407_UART_USR_OE)

void HandleUart(void)
{
 int maxRead = 4;

 volatile uint8 uisr = CPU_RD(MCF5407_UART0_UISR);
 // RX INTERRUPT
 if (uisr & (MCF5407_UART_UIMR_FFULL))
 {
 volatile uint8 usr = CPU_RD(MCF5407_UART0_USR);
 //while FIFO is not empty?
 while (usr & (MCF5407_UART_USR_RXRDY) && (maxRead--) > 0)
 { 
 if (usr & ANY_UART_ERRORS)
 {
 SendCommand(SERIAL_CMD_RST_ERR_STAT);
 }
 g_rxFifo.Insert(CPU_RD(MCF5407_UART0_URB));
 usr = CPU_RD(MCF5407_UART0_USR);
 }
 }

 // TX INTERRUPT
 if (uisr & (MCF5407_UART_UIMR_TXRDY))
 {
 if (g_txFifo.GetCurrentLength() > 0)
 {
 volatile UINT8 usr = CPU_RD(MCF5407_UART0_USR);
 // determine if this buffer descriptor is ready to be loaded 
 if (usr & MCF5407_UART_USR_TXRDY) { // TX Ready Bit Set
 UINT8 byte = g_txFifo.Extract();
 CPU_WR(MCF5407_UART0_UTB, byte);
 }
 }

 }

 if (g_txFifo.IsEmpty())
 {
 TransmitterInterrupts(DISABLE);
 }
}

__declspec( interrupt ) void UartIntHandler(void)
{
 HandleUart();
}

void InstallHandler()
{
 UINT32 *vt = (UINT32 *)(VECTOR_TABLE);
 // Autovector isr 1-7 --> vector number 25-31 (UINT32)
 // isr level 6 == vector 30
 vt[ 30 ] = (UINT32)UartIntHandler;
}

void InitUart()
{
 Receiver(DISABLE);
 Transmitter(DISABLE);
 
 ReceiverInterrupts(DISABLE);
 
 SetInterruptMask(TRUE);
 
 InstallHandler();

 SendCommand(SERIAL_CMD_RX_RESET);
 SendCommand(SERIAL_CMD_TX_RESET);
 
 SendCommand(SERIAL_CMD_RESET_MRP);
 
 CPU_WR(MCF5407_UART0_UACR, 0);
 
 SetBaudrate();

 volatile UINT8 mrp1 = (0x0 << 7) | (0x0 << 6) | (0x1 << 5) | (0x4 << 2) | (0x3 << 0);
 volatile UINT8 mrp2 = (0x0 << 6) | (0x0 << 5) | (0x0 << 4) | (0x7 << 0);
 
 CPU_WR(MCF5407_UART0_UMR, mrp1);
 CPU_WR(MCF5407_UART0_UMR, mrp2);
 
 SendCommand(SERIAL_CMD_RST_ERR_STAT); //reset error status
 SendCommand(SERIAL_CMD_RESET_BCI); //reset break-change interrupt

 UINT8 intLevel = 6;
 UINT8 intPrio = 3;
 UINT8 icrValue = (MCF5407_SIM_ICR_AVEC) | MCF5407_SIM_ICR_IL(intLevel) | (intPrio);
 // Set up the interrupt level and priority
 CPU_WR( UART0_ICR, icrValue );

 SetInterruptMask(FALSE);

 ReceiverInterrupts(ENABLE);
 TransmitterInterrupts(DISABLE);
 
 Receiver(ENABLE);
 Transmitter(ENABLE);
}

int main()
{
 Hardware_Init();
 InitUart();
 
 ReceiverInterrupts(ENABLE);

 while (1)
 {
 if (g_rxFifo.GetCurrentLength() > 0)
 {
 while (!g_rxFifo.IsEmpty() && g_txFifo.GetFree() >= 1)
 {
 g_txFifo.Insert(g_rxFifo.Extract());
 }
 TransmitterInterrupts(ENABLE);
 }
 }

 return 0;
}

void Hardware_Init()
{
 //-------------------------------------------------------------------------
 // Out of reset, only level 7 interrupts are enabled. Enable down to
 // level 3 interrupts (Timer and UART interrupts are enabled)
 //-------------------------------------------------------------------------
 SetSR( 0x2200 );

}

/*-----------------------------------------------------------------------------
| Title: Set CPU Status Register (SR) Value
\*---------------------------------------------------------------------------*/
void SetSR( UINT32 sr )
{
asm {
 move.w d0,sr
 nop
 }
}


/*-----------------------------------------------------------------------------
| Title: Get CPU Status Register (SR) Value
\*---------------------------------------------------------------------------*/
UINT32 GetSR()
{
asm {
 move.w sr,d0
 nop
 }
}

Labels (1)
0 Kudos
Reply
4 Replies

1,341 Views
TomE
Specialist II

There should be some linux serial drivers for this hardware. Google might be able to find you some sources. They certainly aren't in the current distributions.

I found references to there being sources in the ucLinux sources here (reference, not the sources) under "Interrupt-based driver for Wacom Artpad":

My life with the MCF5407 Coldfire Board \\ (draft) 

There might be something in here:

http://en.verysource.com/item/dbug_rar-152755.html 

Tom

0 Kudos
Reply

1,341 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

MCF5407 is a quite old product, we couldn't debug the code.

While, I find MCF5407 UART driver for your reference.

Wish it helps.


Have a great day,
Mike

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
Reply

1,341 Views
jbolduc
Contributor I

Hi,

Thanks for the answer. Unfortunately this driver doesn't use the interrupts, but I still managed to find my problem.

The UART interrupt mask register MCF5407_UART0_UIMR and the UART interrupt pending register MCF5407_UART0_UISR share the exact same address. The read operation returns UISR, not UIMR. So we cannot do this :

void EnableTxInt()

{

   unsigned char uimr = CPU_RD(MCF5407_UART0_UIMR); // WRONG !!!
   uimr |= MCF5407_UART_UIMR_TXRDY; // ENABLE TX INTERRUPT

   CPU_WR(MCF5407_UART0_UIMR, uimr);

}

We should do this instead :

unsigned char g_uimr;

// Initialize g_uimr somewhere...

void EnableTxInt()

{

   g_uimr |= MCF5407_UART_UIMR_TXRDY; // ENABLE TX INTERRUPT

   CPU_WR(MCF5407_UART0_UIMR, g_uimr);

}

If it may help someone else.

0 Kudos
Reply

1,341 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Thanks for the info.

best regards,

Mike

0 Kudos
Reply