static inline int i2c_status(i2c_t *obj) { return I2C_STAT(obj); }
//========================================================================== // The ISR does the actual work. It is not that much work to justify // putting it in the DSR, and it is also not clear whether this would // even work. If an error occurs we try to leave the bus in the same // state as we would if there was no error. //========================================================================== static cyg_uint32 lpc2xxx_i2c_isr(cyg_vector_t vec, cyg_addrword_t data) { cyg_lpc2xxx_i2c_extra* extra = (cyg_lpc2xxx_i2c_extra*)data; cyg_uint8 status; I2C_R8(I2C_STAT(extra), status); switch(status) { case 0x00: // bus error, stop transfer SET_CON(extra, CON_STO); extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_BUS; break; case 0x08: // START sent, send Addr+R/W case 0x10: // ReSTART sent, send Addr+R/W CLR_CON(extra, CON_STA); I2C_W8(I2C_DAT(extra), extra->i2c_addr); break; case 0x18: // Addr ACKed, send data if(extra->i2c_txbuf == NULL) { extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_BUF; cyg_drv_interrupt_mask_intunsafe(vec); cyg_drv_interrupt_acknowledge(vec); return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR; } I2C_W8(I2C_DAT(extra), *extra->i2c_txbuf); extra->i2c_txbuf++; break; case 0x28: // Data ACKed, send more extra->i2c_count--; if(extra->i2c_count == 0) { extra->i2c_flag = I2C_FLAG_FINISH; cyg_drv_interrupt_mask_intunsafe(vec); cyg_drv_interrupt_acknowledge(vec); return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR; } I2C_W8(I2C_DAT(extra), *extra->i2c_txbuf); extra->i2c_txbuf++; break; case 0x50: // Data ACKed, receive more case 0x58: // Data not ACKed, end reception if(extra->i2c_rxbuf == NULL) { extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_BUF; cyg_drv_interrupt_mask_intunsafe(vec); cyg_drv_interrupt_acknowledge(vec); return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR; } I2C_R8(I2C_DAT(extra), *extra->i2c_rxbuf); extra->i2c_rxbuf++; extra->i2c_count--; // fall through case 0x40: // Addr ACKed, receive data if(status == 0x58 || extra->i2c_count == 0) { extra->i2c_flag = I2C_FLAG_FINISH; cyg_drv_interrupt_mask_intunsafe(vec); cyg_drv_interrupt_acknowledge(vec); return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR; } if((extra->i2c_count == 1) && extra->i2c_rxnak) { CLR_CON(extra, CON_AA); } else { SET_CON(extra, CON_AA); } break; case 0x20: // Addr not ACKed case 0x48: // Addr not ACKed SET_CON(extra, CON_STO); // tranfer failed - force stop extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_ADDR; cyg_drv_interrupt_mask_intunsafe(vec); cyg_drv_interrupt_acknowledge(vec); break; case 0x30: // Data not ACKed SET_CON(extra, CON_STO); // tranfer failed - force stop extra->i2c_count++; extra->i2c_txbuf--; extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_DATA; cyg_drv_interrupt_mask_intunsafe(vec); cyg_drv_interrupt_acknowledge(vec); return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR; break; case 0x38: // Arbitration lost extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_LOST; break; default: // lots of unused states extra->i2c_flag = I2C_FLAG_ERROR | I2C_FLAG_UNK; break; } // switch(status) CLR_CON(extra, CON_SI); cyg_drv_interrupt_acknowledge(vec); // // We need to call the DSR only if there is really something to signal, // that means only if extra->i2c_flag != 0 // if (extra->i2c_flag) { return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR; } else { return CYG_ISR_HANDLED; } }