Atmel serial interrupt (at91r40008)

I'm trying to get interupt-driven serial IO working on the Atmel EB40A/AT91R40008. I initialize serial0 this way. In my main loop I am transmitting a character about once per second. I can see the character on the pc that is plugged into 'serial A' on the eb40a. However, no interrupt is ever generated. The US0 bit is enabled in the power-saving register. I'm using a JTAG device to debug the code. I have a breakpoint set in the serial interrupt but the program never gets ther. I also have some timer interrupts going and they work.

What am I missing?

void initSerial(void) { int i; unsigned long ul; unsigned int dummy;

US0_CR = ( US_TXDIS | US_RXDIS | US_RSTTX | US_RSTRX | US_RSTSTA); for (i=1000; i>0; i--);

US0_RCR = 0x00000000; US0_TCR = 0x00000000;

PIO_PDR = MY_PIO_TXD0 | MY_PIO_RXD0; US0_MR = US_CLKS_MCK | // use MCK US_CHRL_8 | // 8 data bits US_CHMODE_NORMAL | US_PAR_NO | // no parity US_NBSTOP_1; // 1 stop bit

dummy = PS_PCSR; dummy |= 0x00000004; PS_PCER = dummy; // enable clock input to baud rate gen (power saving) dummy = dummy ^ 0xffffffff; PS_PCDR = dummy;

US0_IER = US_ENDTX; // Enable ENDTX interrupt (0x10) dummy = ~US_ENDTX; US0_IDR = ~US_ENDTX; // Disable everything else

US0_TPR = (unsigned short)txbuf; US0_TCR = 1; // TXLEN;

US0_BRGR = 430; // 9600 baud at 66 MHz

for(i = 0; i < TXLEN; i++) { txbuf[i] = 0x00; }

US0_CR = US_TXEN; // changes registers: (US0_TPR, US0_TCR)!!!

for (i=1000; i>0; i--);

// Source #2 is USART0

AIC_SMR2 = 0x00000027; // edge triggered / prio = 7 AIC_SVR2 = (unsigned int)serial0_irq; // Address of ISR dummy = 0x00000004; AIC_IECR = dummy; // Enable USART0 interrupt dummy ^= 0xffffffff; AIC_IDCR = dummy; // disable all other interrupts AIC_ICCR = 0x00000004; // Clear any USART0 interrupt

return; }

Reply to
James Johnson
Loading thread data ...

Is this a 16550 emulation?

Reply to
Rick Merrill


Reply to
James Johnson

"James Johnson" skrev i meddelandet news:






Did you check any of the serial routines on the AT91 CD? (Downloadable from

formatting link

Reply to
Ulf Samuelsson


Are you attempting to use the PDC to feed the data out?

Please note that the transfer starts when the TX count is set up. All other registers should be set up before that, including the interrupt set-up.

This is plain wrong:

US0_TPR = (unsigned short)txbuf;

You're casting the buffer address to its 16 least significant bits. The register is 32 bits wide, so the cast should be to uint32_t (or unsigned long).

The interrupt should be level-sensitive (though IIRC, the internal sources do not look at the edge bit).

The idea of separate set and reset ports of a register is to make it simple to control individual bits. Your example:

dummy = PS_PCSR; dummy |= 0x00000004; PS_PCER = dummy; // enable clock input to baud rate gen > dummy = dummy ^ 0xffffffff; PS_PCDR = dummy;

This is a pretty complicated way to do:

PS_PCER = 0x00000004;

Though it is not needed here, you'll get better code if you replace

dummy = dummy ^ 0xffffffff;


dummy = ~dummy;

I'd do the initalizations in a different order:

  1. CPU interrupt disable
  2. Interrupt vector & controller setup
  3. Power control setup
  4. Baud rate and UART setup
  5. CPU interrupt enable
  6. PDC pointer setup
  7. PDC count setup

Did you remember to set up the interrupt vectoring instruction in low memory (ldr pc,[pc,#-0xf20] at the IRQ vector location (0x18))?

Did you remember to enable the CPU interrupts?


Tauno Voipio
tauno voipio (at) iki fi
 Click to see the full signature
Reply to
Tauno Voipio

For now, I'd rather not use the PDC. I just want to send one byte at a time and get an interrupt. I'm not sure how to NOT use the PDC other than set the count to 0. I'm doing that now and I see the characters being transmitted.

I got this from an example that I found. I've changed it to (unsigned long), but for now I'm setting US0_TPR to 0, since I don't really want to use it.

I did have edge triggered interrupts set (AIC_SMR2 = 0x00000027). I tried both

AIC_SMR2 = 0x00000007; and AIC_SMR2 = 0x00000067;

But still no interrupt. Note that I AM getting both timer0 and timer1 interrupts, so interrupts are enabled.

I found some other examples that did it this way. I was doing this in debugging / stepping through the code and I also was thinking that you couldn't do "|=" to write only registers. I discovered that the gnu compiler generates code that does a read of the correct status register, so that this works. Now, I'm writing the code as something like

PS_PCER |= 0x00000004;

I've tried initializing in different orders but so far no luck.

I have this set up. The timer interrupts are working.


BUT. Still no USART interrupt. Any other ideas? Would it help If I posted the values of pertinent registers? I'm using a jtag and can see all of the register values. Everything makes sense except for no serial interrupt.

One thing, however, I tried setting US0_TCR to 1 (since I'm trying to get an interrupt at the end of each byte). But the debugger said that it was still 0. It is a r/w register, so I'm not sure why I was not able to set that register to 1. For now I'm setting US0_TCR and US0_TPR to 0. I get characters transmitted either way by polling.

thanks, Jim

Reply to
James Johnson

and get an interrupt.

that now and I see the

but for now I'm setting

interrupts, so interrupts are

debugging / stepping through

registers. I discovered

register, so that this

values of pertinent

makes sense except

interrupt at the end of

so I'm not sure why I

US0_TPR to 0. I get

Please mail me, so I get a working address. There is little sense to put lengthy pieces of code here.

Please change the address in the sig in an obvious way.

Tauno Voipio
tauno voipio (at) iki fi
 Click to see the full signature
Reply to
Tauno Voipio

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.