Hi, I am using ARM7 Lpc 2148. For a slave receive function in SPI, i am using ISR to get the data from Master . When i used in polling method i got the data from master, slave can receive all the data. When using with ISR, the function doesnt get mapped when an interrupt occurs. Master started txmtng data, I viewed the data in Proteus, SPI debug mode. The slave receives the data, i checked with the status register in slave ,it got set after receiving a data. But ISR function doent start after interrupt occurs. I have configured the VIC for SPI0. I have given the code below, can you please take a look on it and predict where the problem is?.
#include <LPC214X.H> #include "timer.h" #include "lcd.h" void spi_slave_init(void); int8 spi_read(void); int8 Loc,data,m = 6; void SPI_ISR(void)__irq { m = 44; S0SPINT = 0x01; VICVectAddr=0; } int main() { set_clock(); lcd_init(); spi_slave_init(); lcd_command(0xc0); while(1) { if(S0SPINT) { S0SPINT=0x01; lcd_command(0x80); display_hex(S0SPDR,2); } if(S0SPSR&0x80) { lcd_command(0xc1); display_String("SPIF Set"); } else { lcd_command(0xc1); display_String("SPIF not set"); } if(S0SPSR&0x40) { lcd_command(0xc2); display_String("WCOL SET"); } else { lcd_command(0xc2); display_String("WCOL NOT SET"); } if(S0SPSR&0x20) { lcd_command(0xc3); display_String("ROVR SET"); } else { lcd_command(0xc3); display_String("ROVR NOT SET"); } if(S0SPSR&0x10) { lcd_command(0xc4); display_String("MOde fault set"); } else { lcd_command(0xc4); display_String("MODE FAULT NOT SET"); } if(S0SPSR&0x08) { lcd_command(0xc5); lcd_data('ABORT'); } else { lcd_command(0xc5); lcd_data('ABORT not occured'); } if(VICIRQStatus&0x400) { lcd_data('IRQ Set'); } display_hex(m,2); // TO check whether 'm' value changed because if data rcvd it will step into ISR, so that m can change from 6 to 44 value. But this is not working. } } void spi_slave_init() { PINSEL0|=0x00005500; IODIR0|=0xffffffaf; IOCLR0|=0xffffffff; S0SPCR|=0x0088; VICIntEnable = 0x0400; VICVectCntl0 = 0x2A ; //0x20 |0x10; //0x0A VICVectAddr0 = ( unsigned int)SPI_ISR; } int8 spi_read() { if((S0SPSR & 0x20)) {} while(!(S0SPSR & 0x80)); return S0SPDR; }
Note : * SPI Cntrol reg : I have set as Slave, CPHA =1,CPOL =0,8bits reception , and Serial peripheral interrupt enable (SPIE =1 ) . * SPI status Reg - Checkking for all faults and interrupts . * VIC : SPI0 enabled, Address for ISR given, Ctl0 provided for priority. * Checking S0SPINT : When a data rxcvd from master it is getting enabled,but after that i couldnt disable S0SPINT.
"Ctl0 provided for priority." That register is not priority.
Another thing - it's bad practice to enable an interrupt and then after it has been enabled assign the interrupt handler. What if the interrupt is already pending and gets trigged before the address is assigned?
And why are you mixing interrupt-driven and polling code?
Hi, Thanks for your reply.
>> Yes i am wrong in Ctl0, Thanks for your correction.
>> I have just included a slave read function , where i didn't used it in my program.
>> I have made changes by giving like below,
VICVectAddr0 = ( unsigned int)SPI_ISR; VICIntEnable = 0x0400; VICVectCntl0 = 0x2A ; //0x20 |0x10; //0x0A COrrect me if i am wrong.
But eventhough it doesnt works.
As per datasheet this is the info i got for Ctl0:
** VICVectCntl0 Vector control 0 register. Vector Control Registers 0-15 each control one of the 16 vectored IRQ slots. Slot 0 has the highest priority and slot 15 the lowest. ** ---------------- Modified Code: ---------------- Default value of 'm' will be 6, If it enters into ISR it will be updated as 44, in while loop i have displayed 'm ' value .So that to check whether it enters into ISR or not.
Note : As mentioned for UART , I have given the same program flow, it works perfectly. I dont know where i went wrong. Please recheck the registers config. (From my side i checked thorougly, but mapping to ISR is an problem)
Thanks for your valuable time....!!!!!
*************
#include <LPC214X.H> #include "timer.h" #include "lcd.h"
void spi_slave_init(void); int8 Loc,data,m = 6;
void SPI_ISR(void)__irq { S0SPINT = 0x01; m = 44; VICVectAddr=0;
}
int main() { set_clock(); lcd_init(); spi_slave_init();
lcd_command(0xc0);
while(1) { display_hex(m,2); } }
void spi_slave_init() { PINSEL0|=0x00005500; IODIR0|=0xffffffaf; IOCLR0|=0xffffffff; S0SPCR|=0x0088; VICVectAddr0 = ( unsigned int)SPI_ISR; VICIntEnable = 0x0400; VICVectCntl0 = 0x2A ;
VICVectAddr0 = ( unsigned int)SPI_ISR; VICIntEnable = 0x0400; VICVectCntl0 = 0x2A ; //0x20 |0x10; //0x0A
You should enable after you have set up everything else. So not enable before you tell the VIC what function channel 0 will actually have.
Note that IOCLR0 isn't a read/modify/write register with old state you need to save for other bits.
IOCLR0 |= 0xffffffff;
To clear, you just make a write, without first doing a meaningless read and a meaningless bitwise-or operation. So instead:
IOCLR0 = 0xffffffff;
Another thing - don't you think you should touch the relevant registers when you get an interrupt? Like trying to read any received data if the interrupt reason was that new data is available?
Hi,
I am trying with Registers related to SPI, but it doesnt work. Thats why i just used a global variable to check. My intention is to route to ISR routine once interrupt occurs.
I tried by the methods you suggested, do we need to enable some option in Target options in KEIL u4. I have gone through a website, they have mentioned some changes in target option in Linker tab has to be enabled(whenever problem occurs in ISR Routing),
Refer : www.ocfreaks.com/lpc2148-interrupt-problem-issue-fix
Eventhough it doesnt work.
Can you suggest some other corrections ?..!!!!