void STM32_I2C_EV_Interrupt (void* param) // Event Interrupt Handler { INTERRUPT_START // pre: // I2C_SR1_SB | I2C_SR1_ADDR | I2C_SR1_BTF | I2C_CR2_ITBUFEN & (I2C_SR1_RXNE | I2C_SR1_TXE) I2C_HAL_XACTION* xAction = currentI2CXAction; I2C_HAL_XACTION_UNIT* unit = currentI2CUnit; int todo = unit->m_bytesToTransfer; int sr1 = I2Cx->SR1; // read status register int sr2 = I2Cx->SR2; // clear ADDR bit int cr1 = I2Cx->CR1; // initial control register if (unit->IsReadXActionUnit()) { // read transaction if (sr1 & I2C_SR1_SB) { // start bit if (todo == 1) { I2Cx->CR1 = (cr1 &= ~I2C_CR1_ACK); // last byte nack } else if (todo == 2) { I2Cx->CR1 = (cr1 |= I2C_CR1_POS); // prepare 2nd byte nack } UINT8 addr = xAction->m_address << 1; // address bits I2Cx->DR = addr + 1; // send header byte with read bit; } else { if (sr1 & I2C_SR1_ADDR) { // address sent if (todo == 1) { I2Cx->CR1 = (cr1 |= I2C_CR1_STOP); // send stop after single byte } else if (todo == 2) { I2Cx->CR1 = (cr1 &= ~I2C_CR1_ACK); // last byte nack } } else { while (sr1 & I2C_SR1_RXNE) { // data available if (todo == 2) { // 2 bytes remaining I2Cx->CR1 = (cr1 |= I2C_CR1_STOP); // stop after last byte } else if (todo == 3) { // 3 bytes remaining if (!(sr1 & I2C_SR1_BTF)) break; // assure 2 bytes are received I2Cx->CR1 = (cr1 &= ~I2C_CR1_ACK); // last byte nack } UINT8 data = I2Cx->DR; // read data *(unit->m_dataQueue.Push()) = data; // save data unit->m_bytesTransferred++; unit->m_bytesToTransfer = --todo; // update todo sr1 = I2Cx->SR1; // update status register copy } } if (todo == 1) { I2Cx->CR2 |= I2C_CR2_ITBUFEN; // enable I2C_SR1_RXNE interrupt } } } else { // write transaction if (sr1 & I2C_SR1_SB) { // start bit UINT8 addr = xAction->m_address << 1; // address bits I2Cx->DR = addr; // send header byte with write bit; } else { while (todo && (sr1 & I2C_SR1_TXE)) { I2Cx->DR = *(unit->m_dataQueue.Pop()); // next data byte; unit->m_bytesTransferred++; unit->m_bytesToTransfer = --todo; // update todo sr1 = I2Cx->SR1; // update status register copy } if (!(sr1 & I2C_SR1_BTF)) todo++; // last byte not yet sent } } if (todo == 0) { // all received or all sent if (!xAction->ProcessingLastUnit()) { // start next unit I2Cx->CR2 &= ~I2C_CR2_ITBUFEN; // disable I2C_SR1_RXNE interrupt currentI2CUnit = xAction->m_xActionUnits[ xAction->m_current++ ]; I2Cx->CR1 = I2C_CR1_PE | I2C_CR1_START | I2C_CR1_ACK; // send restart } else { xAction->Signal(I2C_HAL_XACTION::c_Status_Completed); // calls XActionStop() } } INTERRUPT_END }
void STM32_I2C_EV_Interrupt (void* param) // Event Interrupt Handler { INTERRUPT_START I2C_HAL_XACTION* xAction = currentI2CXAction; I2C_HAL_XACTION_UNIT* unit = currentI2CUnit; int todo = unit->m_bytesToTransfer; int sr1 = I2Cx->SR1; // read status register int sr2 = I2Cx->SR2; // clear ADDR bit int cr1 = I2Cx->CR1; // initial control register if (unit->IsReadXActionUnit()) { // read transaction if (todo > 0) { if (sr1 & I2C_SR1_SB) { // start bit if (todo == 2) { I2Cx->CR1 = (cr1 |= I2C_CR1_POS); // prepare 2nd byte nack } UINT8 addr = xAction->m_address << 1; // address bits I2Cx->DR = addr + 1; // send header byte with read bit; } else { if (sr1 & I2C_SR1_ADDR) { // address sent if (todo <= 2) { if (todo == 1) cr1 |= I2C_CR1_STOP; // send stop after single byte I2Cx->CR1 = (cr1 &= ~I2C_CR1_ACK); // last byte nack } } else { int n = 0; if (sr1 & I2C_SR1_BTF) { // two bytes available n = (todo & 1) + 1; // todo odd => read two bytes if (todo == 2) n = 2; // todo = 2 => read all if (todo == 3) { I2Cx->CR1 = (cr1 &= ~I2C_CR1_ACK); // last byte nack } } else if (todo == 1 && sr1 & I2C_SR1_RXNE) { // last byte n = 1; I2Cx->CR2 &= ~I2C_CR2_ITBUFEN; // disable I2C_SR1_RXNE interrupts } while (n != 0) { if (todo == 2) { I2Cx->CR1 = (cr1 |= I2C_CR1_STOP); // stop after last byte } UINT8 data = I2Cx->DR; // read data *(unit->m_dataQueue.Push()) = data; // save data unit->m_bytesTransferred++; unit->m_bytesToTransfer = --todo; // update todo n--; } } if (todo == 1) { I2Cx->CR2 |= I2C_CR2_ITBUFEN; // enable I2C_SR1_RXNE interrupt } } } } else { // write transaction if (sr1 & I2C_SR1_SB) { // start bit UINT8 addr = xAction->m_address << 1; // address bits I2Cx->DR = addr; // send header byte with write bit; } else if (sr1 & I2C_SR1_ADDR || sr1 & I2C_SR1_BTF) { // tx idle int n = todo < 2 ? todo : 2; // write at most 2 bytes while (n != 0) { I2Cx->DR = *(unit->m_dataQueue.Pop()); // next data byte; unit->m_bytesTransferred++; unit->m_bytesToTransfer--; // no todo update! n--; } } } if (todo == 0) { if (!xAction->ProcessingLastUnit()) { // start next unit currentI2CUnit = xAction->m_xActionUnits[ xAction->m_current++ ]; I2Cx->CR1 = I2C_CR1_PE | I2C_CR1_START | I2C_CR1_ACK; // send restart } else { xAction->Signal(I2C_HAL_XACTION::c_Status_Completed); // calls XActionStop() } } INTERRUPT_END }
void LPC178X_I2C_Driver::ISR( void* arg ) { UINT8 address; LPC178X_I2C& I2C = LPC178X::I2C(); // read status volatile UINT32 status; I2C_HAL_XACTION* xAction = g_LPC178X_I2C_Driver.m_currentXAction; I2C_HAL_XACTION_UNIT* unit = g_LPC178X_I2C_Driver.m_currentXActionUnit; ASSERT(xAction); ASSERT(unit); status = I2C.I2STAT & 0xFF; switch(status) { case 0x08: // Start Condition transmitted case 0x10: // Repeated Start Condition transmitted // Write Subordinate address and Data direction address = 0xFE & (xAction->m_address << 1); address |= unit->IsReadXActionUnit() ? LPC178X_I2C_Driver::c_DirectionRead : LPC178X_I2C_Driver::c_DirectionWrite; I2C.I2DAT = address; // Clear STA bit I2C.I2CONCLR = LPC178X_I2C::STA; break; case 0x18: // Subordinate Address + W transmitted, Ack received case 0x28: // Data transmitted, Ack received // Write data // transaction completed if(unit->m_bytesToTransfer == 0) { if(xAction->ProcessingLastUnit()) { xAction->Signal( I2C_HAL_XACTION::c_Status_Completed ); } else { MasterXAction_Start( xAction, true ); } } else { WriteToSubordinate( unit ); } break; case 0x20: // Write Address not acknowledged by Subordinate case 0x30: // Data not acknowledged by Subordinate case 0x48: // Read Address not acknowledged by Subordinate xAction->Signal( I2C_HAL_XACTION::c_Status_Aborted ); break; case 0x38: // Arbitration lost xAction->Signal( I2C_HAL_XACTION::c_Status_Aborted ); break; case 0x40: // Subordinate Address + R transmitted, Ack received // if the transaction is one byte only to read, then we must send NAK immediately if(unit->m_bytesToTransfer == 1) { I2C.I2CONCLR = LPC178X_I2C::AA; } else { I2C.I2CONSET = LPC178X_I2C::AA; } break; case 0x50: // Data received, Ack Sent case 0x58: // Data received, NO Ack sent // read next byte ReadFromSubordinate( unit ); if(unit->m_bytesToTransfer == 1) { I2C.I2CONCLR = LPC178X_I2C::AA; } if(unit->m_bytesToTransfer == 0) { if(xAction->ProcessingLastUnit()) { // send transaction stop xAction->Signal( I2C_HAL_XACTION::c_Status_Completed ); } else { // start next MasterXAction_Start( xAction, true ); } } break; case 0x00: // Bus Error // Clear Bus error I2C.I2CONSET = LPC178X_I2C::STO; xAction->Signal( I2C_HAL_XACTION::c_Status_Aborted ); break; default: xAction->Signal( I2C_HAL_XACTION::c_Status_Aborted ); break; } // switch(status) // clear the interrupt flag to start the next I2C transfer I2C.I2CONCLR = LPC178X_I2C::SI; }