|
|
View previous topic :: View next topic |
Author |
Message |
nehallove
Joined: 16 Jan 2008 Posts: 61
|
Re: Int_Global routine for i2c doesn't work |
Posted: Wed Mar 06, 2013 7:16 pm |
|
|
Hi I am trying to use global routine for different interrupts in the same routine. But when i try following i2c clock goes low and it freezes. Collected data at slave is multiple values of same data.
Code: |
#use I2C(SLAVE,sda=PIN_C4,scl=PIN_C3,address=0xB0,SLOW,FORCE_HW)
/*
* We have two kind of interrupts: I2C and UART. I2C have a priority over UART.
* We have a system timer which runs on the Timer Interrupt.
*/
#bit T0IE = 0x00B.5 //! Timer0 Interrupt Enable Bit
#bit I2CE = 0x091.3 //! I2C Interrupt Enable Bit
#bit USART_TX_E = 0x091.4 //! UART TX Interrupt Enable Bit
#bit USART_RX_E = 0x091.5 //! UART RX Interrupt Enable Bit
#bit T0IF = 0x00B.2 //! Timer0 Interrupt Flag Bit
#bit I2CF = 0x011.3 //! I2C Interrupt Flag Bit
#bit USART_TX_F = 0x011.4 //! UART TX Interrupt Flag Bit
#bit USART_RX_F = 0x011.5 //! UART RX Interrupt Flag Bit
#BYTE TXREG = 0x19A //Transmit char
#BYTE RCREG = 0x199 //Receive char
#define I2C_BUF_SIZE 32
#define UART_BUF_SIZE 64
/*
#define LED_ON() output_high(PIN_E0) //! LED On
#define LED_OFF() output_low(PIN_E0) //! LED Off
#define MAX_ARGC 8
*/
unsigned int8 uart_flag=0;
int32 rx_data=0;
int32 test_flag=0;
//! Design Parameters for UART
char uart_rx_buf[UART_BUF_SIZE], *uart_ptr;
//! Design Parameters for I2C
unsigned int8 i2c_state;
unsigned int8 i2c_in_data, i2c_addr;
char i2c_rx_buf[I2C_BUF_SIZE],i2c_tx_buf[I2C_BUF_SIZE], *i2c_rxptr, *i2c_txptr;
char test,incr;
#int_global
//#INT_SSP
void default_isr(){
if(I2CF){ //!Priority 1 Interrupt: I2C
clear_interrupt(INT_SSP);
i2c_state = i2c_isr_state();
if((i2c_state == 0)||(i2c_state == 0x80))
i2c_read();
//! Slave Transmit
if(i2c_state >= 0x80){ //! Master is Requesting Data
test = *i2c_txptr;
i2c_write(*i2c_txptr); //(check/test this statement for syntax correction)
//!currently employed as '\r' but can be changed later
//if((*i2c_txptr == '\r')||(i2c_txptr == (i2c_tx_buf+I2C_BUF_SIZE))){
//i2c_txptr = i2c_tx_buf;
//}
//i2c_txptr++;
}
//! Slave Receive
else if(i2c_state>0){
i2c_in_data = i2c_read();
*i2c_rxptr++ = i2c_in_data;
//!currently employed as '\r' but can be changed later
if((i2c_in_data == '\r')){
i2c_rxptr = i2c_rx_buf;
i2c_in_data = 0;
}
}
}
/*
if(USART_RX_F){ //! Simple UART receiving interrupt routine
clear_interrupt(INT_RDA); //! Clear Interrupt
*uart_ptr++ = RCREG; //! Store data in buffer and update the buffer pointer
if((RCREG == '\r')||(uart_ptr == uart_rx_buf+UART_BUF_SIZE)){ //! Reset back the pointer
uart_ptr = uart_rx_buf;
uart_flag = 1;
}
}
if(T0IF){ //!Priority 3 Interrupt: Timer
;
}
*/
}
void main()
{
char compstr[] = "|";
char str[20];
char * pch;
char * argv[12], argc=0;
float value;
int32 val;
//! Fill out the buffer
for(int k=0; k<8; k++)
i2c_tx_buf[k] = 0xA1;
uart_ptr = uart_rx_buf; //Assign the pointer before you enable the interrupts
i2c_rxptr = i2c_rx_buf; //Assign the pointer before you enable the interrupts
i2c_txptr = i2c_tx_buf; //Assign the pointer before you enable the interrupts
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
enable_interrupts(INT_RDA);
while(1){
};
}
|
In above code if I disable #int_global and enable #int_ssp line. And remove clear_interrupt(INT_SSP) line it works perfectly fine. But then it becomes interrupt routine only for i2c.
In past product code i have used the same approach for different timer and external interrupt and it successfully worked. I don't know what am I doing wrong with the i2c interrupt.
Thank you very much for the help.
nehal _________________ nehal |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Thu Mar 07, 2013 2:23 am |
|
|
Start at the beginning.
If you use #INT_GLOBAL, it becomes _your_ responsibility to save _every_ register used in the interrupt routine(s). The compiler does nothing for you.
Your routine is saving nothing, so will corrupt the status register, W register, page select register, etc. etc., resulting in nothing working....
You need to go through the assembler of every routine you use in the INT_GLOBAL (including simple things like testing the flags etc.), note down every register that is affected, and start your routine with code to save all these. Then before exiting the routine, restore these. In your case this will include things like the table pointer registers.
Then you don't want to clear interrupts at the start of the routines. In the case of INT_SSP, clearing the interrupt, means that i2c_isr_state won't work correctly, since you have changed one of the bits it uses. In the case of the serial handler, the interrupt _cannot be cleared_, until the byte has been read. It'll re-set itself, since the condition that triggers the interrupt is still 'TRUE'. You must handle the interrupt event, _before_ clearing the interrupt flags. This is required by the hardware.
Then, pointer accesses are slow. You do:
Code: |
test = *i2c_txptr;
i2c_write(*i2c_txptr); //(check/test this statement for syntax correction)
//Instead use:
test = *i2c_txptr;
i2c_write(test); //(check/test this statement for syntax correction)
|
You are accessing the same byte twice using pointers, and doubling the amount of work involved....
With the interrupt disable removed, then the i2c_isr_state starts to apparently work, _but_ the code still won't work for real, since as soon as you start actually doing something in the 'main' loop, this will suffer from corrupted values as register contents are destroyed. Also since you are then not clearing the interrupt, the code keeps looping to the I2C routines....
Best Wishes |
|
|
nehallove
Joined: 16 Jan 2008 Posts: 61
|
|
Posted: Fri Mar 08, 2013 3:44 pm |
|
|
Thank you very much Ttelmah. _________________ nehal |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|