EmbeddedRelated.com
Forums

SPI with PDC: can't get ISR to fire

Started by Ken Smith January 13, 2010
I'm using AT91SAM7X256 (and 512) and am trying to use the SPI
peripheral with the PDC (DMA controller for the benefit of search
engines). When a transfer is finished, I want an ISR to fire to let
me know. My toolchain is ARM-ELF-GCC 4.1.1 with Newlib 1.14.0. Here
is the code. The ISR never fires. Can someone tell me why?

void spi1_isr(void) __attribute__((naked));

void spi1_isr(void)
{
portSAVE_CONTEXT();
while (1)
{
// Just turn off the LED to prove that we got here.
LedOff(1);
}
AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);
portRESTORE_CONTEXT();
}
// configure and do the transfer.
AT91F_SPI1_CfgPIO();
AT91F_SPI1_CfgPMC();
AT91F_SPI_Reset(AT91C_BASE_SPI1);
AT91F_SPI_CfgMode(
AT91C_BASE_SPI1,
((unsigned int) 0x20 << 24) | /* DLYBCS */
((unsigned int) 0x0 << 16) | /* peripheral 0 */
AT91C_SPI_MSTR |
AT91C_SPI_PS_FIXED
AT91C_SPI_LLB
);
AT91F_SPI_CfgCs(
AT91C_BASE_SPI1,
0,
0 |
0 |
AT91C_SPI_CSAAT |
AT91C_SPI_BITS_8 |
(MCK / 1000000) << 8 |
0x20 << 16 |
0x40 << 24
);
AT91F_SPI_Enable(AT91C_BASE_SPI1);
enum {transfer_buffer_size = 64};
char spi1_transmit_buffer[transfer_buffer_size];
char spi1_receive_buffer[transfer_buffer_size];
spi1_transmit_buffer[0] = (1 << 7) | 0x11;
portENTER_CRITICAL(); // FreeRTOS critical section. Probably unnecessary.
AT91F_PDC_Open(AT91C_BASE_PDC_SPI1);
AT91F_AIC_ConfigureIt(
AT91C_ID_SPI1,
AT91C_AIC_PRIOR_HIGHEST,
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL,
spi1_isr
);
AT91F_SPI_EnableIt(
AT91C_BASE_SPI1,
AT91C_SPI_TXBUFE |
AT91C_SPI_ENDTX |
AT91C_SPI_TDRE |
AT91C_SPI_TXEMPTY
);
AT91F_SPI_SendFrame(
AT91C_BASE_SPI1,
spi1_transmit_buffer,
count,
0,
0
);
AT91F_SPI_ReceiveFrame(
AT91C_BASE_SPI1,
spi1_receive_buffer,
count,
0,
0
);
AT91F_PDC_EnableTx(AT91C_BASE_PDC_SPI1);
portEXIT_CRITICAL();
What I'm trying to do is just prove the technique so I can extend it
with a useful driver implementation. When I transmit, I don't care
about the received bytes and when I receive, I won't care about the
transmitted bytes. In the above code, I set up the receive buffer
just so the DMA controller has somewhere to put the bytes but if I can
get by without setting up the receive buffer during transmission, I
would prefer to do that.

Warm regards,
Ken
There are some general steps to debugging interrupt issues. The interrupt
system forms a logic tree and you can trace either forwards or backwards
through the tree to see where the disconnect is.

The logical sequence leading to an interrupt are:
1) Are the flags that should trigger the interrupt set? If not, the peripheral
is not getting to the state that triggers the interrupt (eg. buffer full)
2) Are the enables set for those flags? If not, the peripheral will not turn
these states into an interrupt.
3) Is the peripheral interrupt flag set?
4) Is the interupt controller seeing the interrupt flag?
5) Is the interrupt controller enabling that flag?
6) Is the interrupt set up as level sensitive?
7) Is the interrupt controller stuck servicing a different interrupt?
8) Is the interrupt controller interrupting the CPU?
9) Is the CPU's interrupt enable set?
On Thursday 14 January 2010 12:20:42 Ken Smith wrote:
> I'm using AT91SAM7X256 (and 512) and am trying to use the SPI
> peripheral with the PDC (DMA controller for the benefit of search
> engines). When a transfer is finished, I want an ISR to fire to let
> me know. My toolchain is ARM-ELF-GCC 4.1.1 with Newlib 1.14.0. Here
> is the code. The ISR never fires. Can someone tell me why?
>
> void spi1_isr(void) __attribute__((naked));
>
> void spi1_isr(void)
> {
> portSAVE_CONTEXT();
> while (1)
> {
> // Just turn off the LED to prove that we got here.
> LedOff(1);
> }
> AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);
> portRESTORE_CONTEXT();
> }
> // configure and do the transfer.
> AT91F_SPI1_CfgPIO();
> AT91F_SPI1_CfgPMC();
> AT91F_SPI_Reset(AT91C_BASE_SPI1);
> AT91F_SPI_CfgMode(
> AT91C_BASE_SPI1,
> ((unsigned int) 0x20 << 24) | /* DLYBCS */
> ((unsigned int) 0x0 << 16) | /* peripheral 0 */
> AT91C_SPI_MSTR |
> AT91C_SPI_PS_FIXED
> AT91C_SPI_LLB
> );
> AT91F_SPI_CfgCs(
> AT91C_BASE_SPI1,
> 0,
> 0 |
> 0 |
> AT91C_SPI_CSAAT |
> AT91C_SPI_BITS_8 |
> (MCK / 1000000) << 8 |
> 0x20 << 16 |
> 0x40 << 24
> );
> AT91F_SPI_Enable(AT91C_BASE_SPI1);
> enum {transfer_buffer_size = 64};
> char spi1_transmit_buffer[transfer_buffer_size];
> char spi1_receive_buffer[transfer_buffer_size];
> spi1_transmit_buffer[0] = (1 << 7) | 0x11;
> portENTER_CRITICAL(); // FreeRTOS critical section. Probably unnecessary.
> AT91F_PDC_Open(AT91C_BASE_PDC_SPI1);
> AT91F_AIC_ConfigureIt(
> AT91C_ID_SPI1,
> AT91C_AIC_PRIOR_HIGHEST,
> AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL,
> spi1_isr
> );
> AT91F_SPI_EnableIt(
> AT91C_BASE_SPI1,
> AT91C_SPI_TXBUFE |
> AT91C_SPI_ENDTX |
> AT91C_SPI_TDRE |
> AT91C_SPI_TXEMPTY
> );
> AT91F_SPI_SendFrame(
> AT91C_BASE_SPI1,
> spi1_transmit_buffer,
> count,
> 0,
> 0
> );
> AT91F_SPI_ReceiveFrame(
> AT91C_BASE_SPI1,
> spi1_receive_buffer,
> count,
> 0,
> 0
> );
> AT91F_PDC_EnableTx(AT91C_BASE_PDC_SPI1);
> portEXIT_CRITICAL();
> What I'm trying to do is just prove the technique so I can extend it
> with a useful driver implementation. When I transmit, I don't care
> about the received bytes and when I receive, I won't care about the
> transmitted bytes. In the above code, I set up the receive buffer
> just so the DMA controller has somewhere to put the bytes but if I can
> get by without setting up the receive buffer during transmission, I
> would prefer to do that.
>
> Warm regards,
> Ken

On Wed, Jan 13, 2010 at 03:20:42PM -0800, Ken Smith wrote:
> I'm using AT91SAM7X256 (and 512) and am trying to use the SPI
> peripheral with the PDC (DMA controller for the benefit of search
> engines). When a transfer is finished, I want an ISR to fire to let
> me know. My toolchain is ARM-ELF-GCC 4.1.1 with Newlib 1.14.0. Here
> is the code. The ISR never fires. Can someone tell me why?
>
> void spi1_isr(void) __attribute__((naked));
>
> void spi1_isr(void)
> {
> portSAVE_CONTEXT();
> while (1)
> {
> // Just turn off the LED to prove that we got here.
> LedOff(1);
> }
> AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);
> portRESTORE_CONTEXT();
> }
> // configure and do the transfer.
> AT91F_SPI1_CfgPIO();
> AT91F_SPI1_CfgPMC();
> AT91F_SPI_Reset(AT91C_BASE_SPI1);

Have you verified that SPI as such is working?
The X512 and maybe some X256 revisions need reset to be done twice.
See Erata section in the datasheet for details.
I miss setting the SPIEN Flag in CR register.
Maybe this macro is doing two reset and SPIEN, but I would verify
to be sure.

Probably it is done with two reset

There are other SPI errata, which you might want to know about.

> AT91F_SPI_CfgMode(
> AT91C_BASE_SPI1,
> ((unsigned int) 0x20 << 24) | /* DLYBCS */
> ((unsigned int) 0x0 << 16) | /* peripheral 0 */
> AT91C_SPI_MSTR |
> AT91C_SPI_PS_FIXED
> AT91C_SPI_LLB
> );
> AT91F_SPI_CfgCs(
> AT91C_BASE_SPI1,
> 0,
> 0 |
> 0 |
> AT91C_SPI_CSAAT |
> AT91C_SPI_BITS_8 |
> (MCK / 1000000) << 8 |
> 0x20 << 16 |
> 0x40 << 24
> );
> AT91F_SPI_Enable(AT91C_BASE_SPI1);

I asume this macro is senabling clock for SPI1
IIRC clock is required for reset to work.

> enum {transfer_buffer_size = 64};
> char spi1_transmit_buffer[transfer_buffer_size];
> char spi1_receive_buffer[transfer_buffer_size];
> spi1_transmit_buffer[0] = (1 << 7) | 0x11;
> portENTER_CRITICAL(); // FreeRTOS critical section. Probably unnecessary.
> AT91F_PDC_Open(AT91C_BASE_PDC_SPI1);
> AT91F_AIC_ConfigureIt(
> AT91C_ID_SPI1,
> AT91C_AIC_PRIOR_HIGHEST,
> AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL,
> spi1_isr
> );
> AT91F_SPI_EnableIt(
> AT91C_BASE_SPI1,
> AT91C_SPI_TXBUFE |
> AT91C_SPI_ENDTX |
> AT91C_SPI_TDRE |
> AT91C_SPI_TXEMPTY
> );
> AT91F_SPI_SendFrame(
> AT91C_BASE_SPI1,
> spi1_transmit_buffer,
> count,
> 0,
> 0
> );
> AT91F_SPI_ReceiveFrame(
> AT91C_BASE_SPI1,
> spi1_receive_buffer,
> count,
> 0,
> 0
> );
> AT91F_PDC_EnableTx(AT91C_BASE_PDC_SPI1);
> portEXIT_CRITICAL();

I also miss setting up the GPIO pin to work with SPI1 functionality,
but this would just produce a reasonless transfer.

> What I'm trying to do is just prove the technique so I can extend it
> with a useful driver implementation. When I transmit, I don't care
> about the received bytes and when I receive, I won't care about the
> transmitted bytes. In the above code, I set up the receive buffer
> just so the DMA controller has somewhere to put the bytes but if I can
> get by without setting up the receive buffer during transmission, I
> would prefer to do that.

If you don't care about the data and also don't care about the sendbuffer
being overwritten you can setup DMA for RX and TX to the same buffer.
In case of large transfers this can save a lot of buffer space.
If someone knows something like a /dev/null like memory area in
AT91SAM7* and AT91RM9200 please drop me a note.

--
B.Walter http://www.bwct.de
Modbus/TCP Ethernet I/O Baugruppen, ARM basierte FreeBSD Rechner uvm.
On Thursday 14 January 2010 01:20:42 am Ken Smith wrote:
> I'm using AT91SAM7X256 (and 512) and am trying to use the SPI
> peripheral with the PDC (DMA controller for the benefit of search
> engines). When a transfer is finished, I want an ISR to fire to let
> me know. My toolchain is ARM-ELF-GCC 4.1.1 with Newlib 1.14.0. Here
> is the code. The ISR never fires. Can someone tell me why?
>

Bernd Walter's errata suggestion is a big possibility. Some minor comments:

> void spi1_isr(void) __attribute__((naked));
>
> void spi1_isr(void)
> {
> portSAVE_CONTEXT();
> while (1)
> {
> // Just turn off the LED to prove that we got here.
> LedOff(1);
> }
> AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);
> portRESTORE_CONTEXT();
> }
>

FYI, C code is not allowed in 'naked' functions. You should wrap your C code
in another not inlined function.

>
> // configure and do the transfer.
> AT91F_SPI1_CfgPIO();
> AT91F_SPI1_CfgPMC();
> AT91F_SPI_Reset(AT91C_BASE_SPI1);
> AT91F_SPI_CfgMode(
> AT91C_BASE_SPI1,
> ((unsigned int) 0x20 << 24) | /* DLYBCS */
> ((unsigned int) 0x0 << 16) | /* peripheral 0 */
> AT91C_SPI_MSTR |
> AT91C_SPI_PS_FIXED
> AT91C_SPI_LLB
> );
> AT91F_SPI_CfgCs(
> AT91C_BASE_SPI1,
> 0,
> 0 |
> 0 |
> AT91C_SPI_CSAAT |
> AT91C_SPI_BITS_8 |
> (MCK / 1000000) << 8 |
> 0x20 << 16 |
> 0x40 << 24
> );
> AT91F_SPI_Enable(AT91C_BASE_SPI1);
> enum {transfer_buffer_size = 64};
> char spi1_transmit_buffer[transfer_buffer_size];
> char spi1_receive_buffer[transfer_buffer_size];
> spi1_transmit_buffer[0] = (1 << 7) | 0x11;
> portENTER_CRITICAL(); // FreeRTOS critical section. Probably unnecessary.
> AT91F_PDC_Open(AT91C_BASE_PDC_SPI1);
> AT91F_AIC_ConfigureIt(
> AT91C_ID_SPI1,
> AT91C_AIC_PRIOR_HIGHEST,
> AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL,
> spi1_isr
> );

I think 'AT91F_AIC_ConfigureIt' does not touch AT91C_BASE_AIC->AIC_IECR so
interrupt is enabled by this call. Our library versions are not the same so
I'm not sure but checking your version may help.

> AT91F_SPI_EnableIt(
> AT91C_BASE_SPI1,
> AT91C_SPI_TXBUFE |
> AT91C_SPI_ENDTX |
> AT91C_SPI_TDRE |
> AT91C_SPI_TXEMPTY
> );
> AT91F_SPI_SendFrame(
> AT91C_BASE_SPI1,
> spi1_transmit_buffer,
> count,
> 0,
> 0
> );
> AT91F_SPI_ReceiveFrame(
> AT91C_BASE_SPI1,
> spi1_receive_buffer,
> count,
> 0,
> 0
> );
> AT91F_PDC_EnableTx(AT91C_BASE_PDC_SPI1);
> portEXIT_CRITICAL();
> What I'm trying to do is just prove the technique so I can extend it
> with a useful driver implementation. When I transmit, I don't care
> about the received bytes and when I receive, I won't care about the
> transmitted bytes. In the above code, I set up the receive buffer
> just so the DMA controller has somewhere to put the bytes but if I can
> get by without setting up the receive buffer during transmission, I
> would prefer to do that.
>

Then why are you calling 'AT91F_SPI_ReceiveFrame' ?

Regards,
Caglar

> Warm regards,
> Ken
>
I'll try to address each of the excellent responses.

On Wed, Jan 13, 2010 at 10:39 PM, Caglar Akyuz
wrote:
> On Thursday 14 January 2010 01:20:42 am Ken Smith wrote:
>> I'm using AT91SAM7X256 (and 512) and am trying to use the SPI
>> peripheral with the PDC (DMA controller for the benefit of search
>> engines).  When a transfer is finished, I want an ISR to fire to let
>> me know.  My toolchain is ARM-ELF-GCC 4.1.1 with Newlib 1.14.0.  Here
>> is the code.  The ISR never fires.  Can someone tell me why?
>> Bernd Walter's errata suggestion is a big possibility. Some minor comments:

I tried adding two resets. The other errata don't seem to affect my
setup. So far no ISR.

>> void spi1_isr(void) __attribute__((naked));
>>
>> void spi1_isr(void)
>> {
>>     portSAVE_CONTEXT();
>>     while (1)
>>     {
>>         // Just turn off the LED to prove that we got here.
>>         LedOff(1);
>>     }
>>     AT91F_AIC_AcknowledgeIt(AT91C_BASE_AIC);
>>     portRESTORE_CONTEXT();
>> }
>> FYI, C code is not allowed in 'naked' functions. You should wrap your C code
> in another not inlined function.
There are other naked functions that are implemented in C servicing
other interrupts in my code but I'll try your suggestion.

>> // configure and do the transfer.
>> AT91F_SPI1_CfgPIO();
>> AT91F_SPI1_CfgPMC();
>> AT91F_SPI_Reset(AT91C_BASE_SPI1);
>> AT91F_SPI_CfgMode(
>>     AT91C_BASE_SPI1,
>>     ((unsigned int) 0x20 << 24) | /* DLYBCS */
>>     ((unsigned int) 0x0 << 16) | /* peripheral 0 */
>>     AT91C_SPI_MSTR |
>>     AT91C_SPI_PS_FIXED
>>     AT91C_SPI_LLB
>> );
>> AT91F_SPI_CfgCs(
>>     AT91C_BASE_SPI1,
>>     0,
>>     0 |
>>     0 |
>>     AT91C_SPI_CSAAT |
>>     AT91C_SPI_BITS_8 |
>>     (MCK / 1000000) << 8 |
>>     0x20 << 16 |
>>     0x40 << 24
>> );
>> AT91F_SPI_Enable(AT91C_BASE_SPI1);
>> enum {transfer_buffer_size = 64};
>> char spi1_transmit_buffer[transfer_buffer_size];
>> char spi1_receive_buffer[transfer_buffer_size];
>> spi1_transmit_buffer[0] = (1 << 7) | 0x11;
>> portENTER_CRITICAL(); // FreeRTOS critical section.  Probably unnecessary.
>> AT91F_PDC_Open(AT91C_BASE_PDC_SPI1);
>> AT91F_AIC_ConfigureIt(
>>     AT91C_ID_SPI1,
>>     AT91C_AIC_PRIOR_HIGHEST,
>>     AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL,
>>     spi1_isr
>> );
>
> I think 'AT91F_AIC_ConfigureIt'  does not touch AT91C_BASE_AIC->AIC_IECR so
> interrupt is enabled by this call. Our library versions are not the same so
> I'm not sure but checking your version may help.

Correct.

>> AT91F_SPI_EnableIt(
>>     AT91C_BASE_SPI1,
>>     AT91C_SPI_TXBUFE |
>>     AT91C_SPI_ENDTX |
>>     AT91C_SPI_TDRE |
>>     AT91C_SPI_TXEMPTY
>> );

I incorrectly believed this enabled the interrupt in every way. I
have added this line:

AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SPI1);

immediately after AT91F_AIC_ConfigureIt.

> Then why are you calling 'AT91F_SPI_ReceiveFrame' ?

I was worried that, since SPI can only transfer and receive
simultaneously, that having NULL pointers for the receive buffer would
cause problems. Is this an invalid assumption?

ks
On Wed, Jan 13, 2010 at 4:46 PM, Bernd Walter wrote:

> Have you verified that SPI as such is working?
>

Yes. This is a rewrite for an existing driver that doesn't use DMA or
interrupts. That driver works so I believe the SPI peripheral works.
> The X512 and maybe some X256 revisions need reset to be done twice.
> See Erata section in the datasheet for details.
> I miss setting the SPIEN Flag in CR register.
> Maybe this macro is doing two reset and SPIEN, but I would verify
> to be sure.
>
> Probably it is done with two reset
>

Thanks for pointing this out. Yes, I'm now resetting twice but I still
don't have the interrupts working.
> There are other SPI errata, which you might want to know about.
>

Good point. Most of the other errata involve configurations that I'm not
using but the reset one is definitely interesting.
> > AT91F_SPI_CfgMode(
> > AT91C_BASE_SPI1,
> > ((unsigned int) 0x20 << 24) | /* DLYBCS */
> > ((unsigned int) 0x0 << 16) | /* peripheral 0 */
> > AT91C_SPI_MSTR |
> > AT91C_SPI_PS_FIXED
> > AT91C_SPI_LLB
> > );
> > AT91F_SPI_CfgCs(
> > AT91C_BASE_SPI1,
> > 0,
> > 0 |
> > 0 |
> > AT91C_SPI_CSAAT |
> > AT91C_SPI_BITS_8 |
> > (MCK / 1000000) << 8 |
> > 0x20 << 16 |
> > 0x40 << 24
> > );
> > AT91F_SPI_Enable(AT91C_BASE_SPI1);
>
> I asume this macro is senabling clock for SPI1
> IIRC clock is required for reset to work.
>

The call to AT91F_SPI1_CfgPMC turns on the peripheral clock in my
implementation.
> I also miss setting up the GPIO pin to work with SPI1 functionality,
> but this would just produce a reasonless transfer.
>

The call to AT91F_SPI1_CfgPIO enables the appropriate PIO to work with the
SPI1 peripheral.
> > What I'm trying to do is just prove the technique so I can extend it
> > with a useful driver implementation. When I transmit, I don't care
> > about the received bytes and when I receive, I won't care about the
> > transmitted bytes. In the above code, I set up the receive buffer
> > just so the DMA controller has somewhere to put the bytes but if I can
> > get by without setting up the receive buffer during transmission, I
> > would prefer to do that.
>
> If you don't care about the data and also don't care about the sendbuffer
> being overwritten you can setup DMA for RX and TX to the same buffer.
> In case of large transfers this can save a lot of buffer space.
> If someone knows something like a /dev/null like memory area in
> AT91SAM7* and AT91RM9200 please drop me a note.
>

This is a good point. I have read elsewhere that you can disable reception
at the hardware level by turning the PIO line for MISO back into a GPIO.
This may be safer than using the same buffer for both transfer and receive.

ks
On Wed, Jan 13, 2010 at 4:43 PM, Charles Manning wrote:

> 1) Are the flags that should trigger the interrupt set? If not, the
> peripheral
> is not getting to the state that triggers the interrupt (eg. buffer full)
>
The SPI1 SR shows some of the end of transmission flags set. I'll go
through them all to make sure they transition from unset to set.

> 2) Are the enables set for those flags? If not, the peripheral will not
> turn
> these states into an interrupt.
>
Yes, I've enabled all of the end of transmission and transmit data register
empty interrupts.

> 3) Is the peripheral interrupt flag set?
>
I am enabling the peripheral interrupt like this.

AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SPI1);
AT91F_SPI_EnableIt(AT91C_BASE_SPI1, AT91C_SPI_TXBUFE | AT91C_SPI_TDRE
| AT91C_SPI_TXEMPTY);

> 4) Is the interupt controller seeing the interrupt flag?
> 5) Is the interrupt controller enabling that flag?
>
How can I determine these?

> 6) Is the interrupt set up as level sensitive?
>
Yes. I'm passing the flag AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL
to AT91F_AIC_ConfigureIt.

> 7) Is the interrupt controller stuck servicing a different interrupt?
>
I don't believe so. How can I determine this?

> 8) Is the interrupt controller interrupting the CPU?
>
I don't know. How can I check?

> 9) Is the CPU's interrupt enable set?
>
I don't know of a CPU-wide interrupt enable bit. Which register is it? The
datasheet for my processor says the AIC is always powered on and clocked.
Perhaps it is always enabled?

ks
I was not really expecting a thread from this, but more suggesting a way of
partitioning the problem to hunt down what is happening.

For example, the double reset erratum would show up as the peripheral flags
not being correct.

Even though you are calling the code it is also worth verifying that the
registers actually hold what you expect. Sometimes a sequence of operations
can end up with something important being reset. As Lord Kelvin said: "To
measure is to know".

But, since you ask, see below:

On Friday 15 January 2010 08:04:26 Ken Smith wrote:
> On Wed, Jan 13, 2010 at 4:43 PM, Charles Manning
wrote:
> > 1) Are the flags that should trigger the interrupt set? If not, the
> > peripheral
> > is not getting to the state that triggers the interrupt (eg. buffer full)
>
> The SPI1 SR shows some of the end of transmission flags set. I'll go
> through them all to make sure they transition from unset to set.
>
> > 2) Are the enables set for those flags? If not, the peripheral will not
> > turn
> > these states into an interrupt.
>
> Yes, I've enabled all of the end of transmission and transmit data register
> empty interrupts.
>
> > 3) Is the peripheral interrupt flag set?
>
> I am enabling the peripheral interrupt like this.
>
> AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SPI1);
> AT91F_SPI_EnableIt(AT91C_BASE_SPI1, AT91C_SPI_TXBUFE | AT91C_SPI_TDRE
>
> | AT91C_SPI_TXEMPTY);
> |
> > 4) Is the interupt controller seeing the interrupt flag?
> > 5) Is the interrupt controller enabling that flag?
>
> How can I determine these?

Look at the various AIC registers.
AIC_ISR: which interrupt is currently being serviced.
AIC_IPR: Ipending register will tell you if the AIC has seen the interrupt.
AIC_IMR: mask register.
AIC_CISR: is the AIC trying to interrupt the core?

>
> > 6) Is the interrupt set up as level sensitive?
>
> Yes. I'm passing the flag AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL
> to AT91F_AIC_ConfigureIt.

Check the relevant AIC_SMRx anyway.

>
> > 7) Is the interrupt controller stuck servicing a different interrupt?
>
> I don't believe so. How can I determine this?
AIC_ISR and AIC_CISR

>
> > 8) Is the interrupt controller interrupting the CPU?
>
> I don't know. How can I check?
AIC_CISR
>
> > 9) Is the CPU's interrupt enable set?

Look at the CPU register.

> I don't know of a CPU-wide interrupt enable bit. Which register is it?
> The datasheet for my processor says the AIC is always powered on and
> clocked. Perhaps it is always enabled?
No.
The AIC is an interrupt controller (a peripheral). This is **not** the same as
the CPU.

The AIC filters the system interrupt stream, then attempts to interrupt the
CPU.
The CPU only listens to the AIC if the CPU interrupt is enabled. If the I bit
in the CPSR is set then the interrupt is disabled.

Another debug thing to do is to use the AIC_ISCR to force the interrupt to
trigger in the AIC. If you see the ISR code fire then this means the the AIC
to CPU part is working and something is wrong in the peripheral set up.

Hope that helps

Charles

On Thu, Jan 14, 2010 at 2:35 PM, Charles Manning wrote:

> > > 9) Is the CPU's interrupt enable set?
>
> Look at the CPU register.
>

I was with you until this point. What is the CPU register on this platform?
> > I don't know of a CPU-wide interrupt enable bit. Which register is it?
> > The datasheet for my processor says the AIC is always powered on and
> > clocked. Perhaps it is always enabled?
> No.
> The AIC is an interrupt controller (a peripheral). This is **not** the same
> as
> the CPU.
>

Yes, I understand that the AIC is a peripheral and distinct from the CPU.
The reason I claim it is always powered on is this line from the datasheet.

"The Advanced Interrupt Controller is continuously clocked. The Power
Management Controller has no effect on the Advanced Interrupt Controller
behavior."
> Hope that helps
>

> Charles
>

It does. Thank you, Charles.

ks
On Friday 15 January 2010 12:19:24 Ken Smith wrote:
> On Thu, Jan 14, 2010 at 2:35 PM, Charles Manning
wrote:
> > > > 9) Is the CPU's interrupt enable set?
> >
> > Look at the CPU register.
>
> I was with you until this point. What is the CPU register on this
> platform?

cpsr (== current processor status register)

This will show up as one of the registers.

Do you have a debugger? If so, do whatever you need to see "show registers".

The I bit is bit 6.

>
> > > I don't know of a CPU-wide interrupt enable bit. Which register is it?
> > > The datasheet for my processor says the AIC is always powered on and
> > > clocked. Perhaps it is always enabled?
> >
> > No.
> > The AIC is an interrupt controller (a peripheral). This is **not** the
> > same as
> > the CPU.
>
> Yes, I understand that the AIC is a peripheral and distinct from the CPU.
> The reason I claim it is always powered on is this line from the
> datasheet.
>
> "The Advanced Interrupt Controller is continuously clocked. The Power
> Management Controller has no effect on the Advanced Interrupt Controller
> behavior."

While it may be on, enabled, and clocking, the AIC has various masks etc that
govern its behavior.
>
> > Hope that helps
> >
> >
> > Charles
>
> It does. Thank you, Charles.
>
> ks