I have written a uart polling receive demo on 5748G, and now want to use receive interrupt.
Previously in the main function there is:
if(checkLINFlexD_2())
d[0]=rxLINFlexD_2();
txLINFlexD_2(d[0]);
GPIO_toggle();
The demo works well on PC, if I send 5748G a byte, I can receive it back.
Then I and this to the initialize function:
LINFlexD_2.LINIER.B.DTIE = 1; /* Enable UART2 TX Interrupt */
LINFlexD_2.LINIER.B.DRIE=1; /* Enable UART2 RX Interrupt*/
It is said that this will enable an interrupt when uart2 receives message. If I don't add a interrupt function, the chip will enter a while(1) loop when interrupt occurs, right? But this is not the case since the polling function still works, and I can still receive a message when I send it on PC.
解決済! 解決策の投稿を見る。
In the Freescale examples (AN4830) all IRQs have default handlers for projects, demonstrating IRQ usage. I guess that xinweichang missed INTC initialization or something else. Enabling of IRQ through LINFlex configuration is not sufficient to get interrupt working. In addition, I don't see in the message above which core is in use. If core used is not Core0, then interrupt handling should be also directed to the right core...
I'm attaching one example (based on Freescale example, published some time ago). This one uses PIT interrupt, so controller is configured to handle IRQs properly.
xinweichang, code below configures LINFlex to use interrupts. It is directly taken from the OS driver I wrote, but you'll get the idea:
static void mpc57xx_linflex_init(SerialDriver *sdp, const SerialConfig *config) {
uint32_t div;
volatile struct LINFlexD_tag *linflexp = sdp->linflexp;
sdp->errNoise = sdp->errParity = sdp->errOverRun = sdp->errFraming = sdp->errBreak = 0;
/* Enters the configuration mode.*/
linflexp->LINCR1.B.INIT = 1; /* Put LIN in INIT mode */
linflexp->LINCR1.B.SLEEP = 0; /* No sleep */
/* Configures the LINFlex in UART mode with all the required parameters.*/
linflexp->UARTCR.B.UART = 1; /* Switch first to UART */
linflexp->UARTCR.R = MPC57XX_UARTCR_UART | MPC57XX_UARTCR_RXEN | MPC57XX_UARTCR_RFBM | config->mode;
div = sdp->clock / config->speed;
linflexp->LINIBRR.R = (uint16_t)(div >> 4); /* Integer divider. */
linflexp->LINFBRR.R = (uint16_t)(div & 15); /* Fractional divider. */
linflexp->UARTSR.R = 0xFFFF; /* Clearing UARTSR register.*/
linflexp->LINIER.R = MPC57XX_LINIER_DTIE | MPC57XX_LINIER_DRIE |
MPC57XX_LINIER_BOIE | MPC57XX_LINIER_FEIE |
MPC57XX_LINIER_SZIE; /* Interrupts enabled. */
/* Leaves the configuration mode.*/
linflexp->LINCR1.R = 0; /* Put LIN in NORM mode */
}
This is the receive interrupt routine:
static void mpc57xxxx_serve_rxi_interrupt(SerialDriver *sdp) {
flagsmask_t sts = 0;
uint16_t sr = sdp->linflexp->UARTSR.R;
sdp->linflexp->UARTSR.R = MPC57XX_UARTSR_NF | MPC57XX_UARTSR_DRF |
MPC57XX_UARTSR_PE0;
if (sr & MPC57XX_UARTSR_NF) {
sts |= SD_NOISE_ERROR;
sdp->errNoise++;
}
if (sr & MPC57XX_UARTSR_PE0) {
sts |= SD_PARITY_ERROR;
sdp->errParity++;
}
DISABLE_INTERRUPTS();
if (sts)
chnAddFlagsI(sdp, sts);
if (sr & MPC57XX_UARTSR_DRF) {
sdIncomingDataI(sdp, sdp->linflexp->BDRM.B.DATA4);
sdp->linflexp->UARTSR.R = MPC57XX_UARTSR_RMB;
}
ENABLE_INTERRUPTS();
}
This is the transmit interrupt routine:
static void mpc57xxxx_serve_txi_interrupt(SerialDriver *sdp) {
msg_t b;
sdp->linflexp->UARTSR.R = MPC57XX_UARTSR_DTF;
DISABLE_INTERRUPTS();
b = chOQGetI(&sdp->oqueue);
if (b < Q_OK) {
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
sdp->linflexp->UARTCR.B.TxEn = 0;
} else {
sdp->linflexp->BDRL.B.DATA0 = b;
}
ENABLE_INTERRUPTS();
}
Don't forget that you have to handle error interrupt as well. In addition to all initialization done here, you have to set IRQ priority for the core which will handle the IRQ like this:
INTC.
INTC.PSR[vector].B.PRC_SELN<core> = 1;
INTC.PSR[vector].B.PRIN = <priority>;
Good luck!
I'm trying to test out the UART peripheral on MPC5748G, but I’m stuck at where I’m trying to read data from the LINFlexD_7.BDRM.B.DATA4 data buffer.
My requirement: Try to transmit and receive 9 bytes of hex values as shown below.
TxBuffer[9] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19}
I am attempting to read all 9 bytes using the above Rx ISR, but I am only receiving the first byte repeatedly, which is 0x11.
Please review my Uart7_Rx_Isr code below:
In the Freescale examples (AN4830) all IRQs have default handlers for projects, demonstrating IRQ usage. I guess that xinweichang missed INTC initialization or something else. Enabling of IRQ through LINFlex configuration is not sufficient to get interrupt working. In addition, I don't see in the message above which core is in use. If core used is not Core0, then interrupt handling should be also directed to the right core...
I'm attaching one example (based on Freescale example, published some time ago). This one uses PIT interrupt, so controller is configured to handle IRQs properly.
xinweichang, code below configures LINFlex to use interrupts. It is directly taken from the OS driver I wrote, but you'll get the idea:
static void mpc57xx_linflex_init(SerialDriver *sdp, const SerialConfig *config) {
uint32_t div;
volatile struct LINFlexD_tag *linflexp = sdp->linflexp;
sdp->errNoise = sdp->errParity = sdp->errOverRun = sdp->errFraming = sdp->errBreak = 0;
/* Enters the configuration mode.*/
linflexp->LINCR1.B.INIT = 1; /* Put LIN in INIT mode */
linflexp->LINCR1.B.SLEEP = 0; /* No sleep */
/* Configures the LINFlex in UART mode with all the required parameters.*/
linflexp->UARTCR.B.UART = 1; /* Switch first to UART */
linflexp->UARTCR.R = MPC57XX_UARTCR_UART | MPC57XX_UARTCR_RXEN | MPC57XX_UARTCR_RFBM | config->mode;
div = sdp->clock / config->speed;
linflexp->LINIBRR.R = (uint16_t)(div >> 4); /* Integer divider. */
linflexp->LINFBRR.R = (uint16_t)(div & 15); /* Fractional divider. */
linflexp->UARTSR.R = 0xFFFF; /* Clearing UARTSR register.*/
linflexp->LINIER.R = MPC57XX_LINIER_DTIE | MPC57XX_LINIER_DRIE |
MPC57XX_LINIER_BOIE | MPC57XX_LINIER_FEIE |
MPC57XX_LINIER_SZIE; /* Interrupts enabled. */
/* Leaves the configuration mode.*/
linflexp->LINCR1.R = 0; /* Put LIN in NORM mode */
}
This is the receive interrupt routine:
static void mpc57xxxx_serve_rxi_interrupt(SerialDriver *sdp) {
flagsmask_t sts = 0;
uint16_t sr = sdp->linflexp->UARTSR.R;
sdp->linflexp->UARTSR.R = MPC57XX_UARTSR_NF | MPC57XX_UARTSR_DRF |
MPC57XX_UARTSR_PE0;
if (sr & MPC57XX_UARTSR_NF) {
sts |= SD_NOISE_ERROR;
sdp->errNoise++;
}
if (sr & MPC57XX_UARTSR_PE0) {
sts |= SD_PARITY_ERROR;
sdp->errParity++;
}
DISABLE_INTERRUPTS();
if (sts)
chnAddFlagsI(sdp, sts);
if (sr & MPC57XX_UARTSR_DRF) {
sdIncomingDataI(sdp, sdp->linflexp->BDRM.B.DATA4);
sdp->linflexp->UARTSR.R = MPC57XX_UARTSR_RMB;
}
ENABLE_INTERRUPTS();
}
This is the transmit interrupt routine:
static void mpc57xxxx_serve_txi_interrupt(SerialDriver *sdp) {
msg_t b;
sdp->linflexp->UARTSR.R = MPC57XX_UARTSR_DTF;
DISABLE_INTERRUPTS();
b = chOQGetI(&sdp->oqueue);
if (b < Q_OK) {
chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
sdp->linflexp->UARTCR.B.TxEn = 0;
} else {
sdp->linflexp->BDRL.B.DATA0 = b;
}
ENABLE_INTERRUPTS();
}
Don't forget that you have to handle error interrupt as well. In addition to all initialization done here, you have to set IRQ priority for the core which will handle the IRQ like this:
INTC.
INTC.PSR[vector].B.PRC_SELN<core> = 1;
INTC.PSR[vector].B.PRIN = <priority>;
Good luck!
Thank you very much for giving me so much details:smileyhappy:.
I am using core0 with other core closed, and have done the following:
1. add a interrupt function to intc_SW_mode_isr_vectors_MPC5748G.C:
(uint32_t) &uart2_rx_interrupt, /* Vector # 382 LinFlex2_0 LinFlex_2_RXI */
2. enable rx interrupt in the initLINFlexD functioin:
LINFlexD_2.LINIER.B.DRIE=1; /* Enable UART2 RX Interrupt*/
3. call the xcptn_xmpl() function in main():
int main(void)
{
int i,j;
unsigned char d[100];
MC_ME.RUN_PC[0].R = 0x000000fe;
system160mhz();
InitMCU();
initGPIO();
initLINFlexD_2(80, 115200);
xcptn_xmpl (); /* Configure and Enable Interrupts */
for(;;) {
if(checkLINFlexD_2()){
d[0]=rxLINFlexD_2();
txLINFlexD_2(d[0]);
}
}
return 0;
}
Is there something I still missed?
I don't know what is in the xcptn_xmpl() function, but would be nice to have somewhere:
INTC.PSR[382].B.PRC_SELN0 = 1; INTC.PSR[382].B.PRC_SELN1 = 0; INTC.PSR[382].B.PRC_SELN2 = 0;
INTC.PSR[383].B.PRC_SELN0 = 1; INTC.PSR[383].B.PRC_SELN1 = 0; INTC.PSR[383].B.PRC_SELN2 = 0;
INTC.PSR[384].B.PRC_SELN0 = 1; INTC.PSR[384].B.PRC_SELN1 = 0; INTC.PSR[384].B.PRC_SELN2 = 0;
INTC.PSR[382].B.PRIN = 8;
INTC.PSR[383].B.PRIN = 8;
INTC.PSR[384].B.PRIN = 8;
Let me know if this helps.
Finally I found the problem is I forgot to set interrupt priority, which you mentioned at first time:smileyconfused:. On mc9s12xep100 the interrupt setting is rather simple, so I take it for granted that there is a default interrupt priority. Thank you for spending so much time on my question!:smileyhappy:
Hi,
if you enable interrupt and do not implement interrupt handler, micro does not respond to interrupt flag and continue with the actual task.
For example, if micro executes some function and interrupt occurs, micro continues with executing the function. There is no reaction to the interrupt.
Regards,
Martin