/** * @brief Ready interrupt handler * * @param[in] nandp pointer to the @p NANDDriver object * * @notapi */ static void nand_isr_handler (NANDDriver *nandp) { osalSysLockFromISR(); #if !STM32_NAND_USE_EXT_INT osalDbgCheck(nandp->nand->SR & FSMC_SR_IRS); /* spurious interrupt happened */ nandp->nand->SR &= ~FSMC_SR_IRS; #endif switch (nandp->state){ case NAND_READ: nandp->state = NAND_DMA_RX; dmaStartMemCopy(nandp->dma, nandp->dmamode, nandp->map_data, nandp->rxdata, nandp->datalen); /* thread will be waked up from DMA ISR */ break; case NAND_ERASE: /* NAND reports about erase finish */ nandp->state = NAND_READY; wakeup_isr(nandp); break; case NAND_PROGRAM: /* NAND reports about page programming finish */ nandp->state = NAND_READY; wakeup_isr(nandp); break; default: osalSysHalt("Unhandled case"); break; } osalSysUnlockFromISR(); }
/** * @brief I2C shared ISR code. * * @param[in] i2cp pointer to the @p I2CDriver object * * @notapi */ static void i2c_lld_serve_interrupt(I2CDriver *i2cp) { uint32_t sr; sr = AT91C_BASE_TWI->TWI_SR; /* this masking doing in official Atmel driver. Is it needed ??? */ sr &= AT91C_BASE_TWI->TWI_IMR; if (sr & AT91C_TWI_NACK){ i2cp->errors |= I2CD_ACK_FAILURE; wakeup_isr(i2cp, RDY_RESET); return; } if (sr & AT91C_TWI_RXRDY){ _i2c_lld_serve_rx_interrupt(i2cp); } else if (sr & AT91C_TWI_TXRDY){ _i2c_lld_serve_tx_interrupt(i2cp); } else if (sr & AT91C_TWI_TXCOMP){ AT91C_BASE_TWI->TWI_IDR = AT91C_TWI_TXCOMP; wakeup_isr(i2cp, RDY_OK); } else chDbgPanic("Invalid value"); }
void i2c_lld_serve_interrupt(I2CDriver *i2cp) { UNUSED(i2cp); bscdevice_t *device = i2cp->device; uint32_t status = device->status; if (status & (BSC_CLKT | BSC_ERR)) { // TODO set error flags wakeup_isr(i2cp, RDY_RESET); } else if (status & BSC_DONE) { while ((status & BSC_RXD) && (i2cp->rxidx < i2cp->rxbytes)) i2cp->rxbuf[i2cp->rxidx++] = device->dataFifo; device->control = 0; device->status = BSC_CLKT | BSC_ERR | BSC_DONE; wakeup_isr(i2cp, RDY_OK); } else if (status & BSC_TXW) { while ((i2cp->txidx < i2cp->txbytes) && (status & BSC_TXD)) device->dataFifo = i2cp->txbuf[i2cp->txidx++]; } else if (status & BSC_RXR) { while ((i2cp->rxidx < i2cp->rxbytes) && (status & BSC_RXD)) i2cp->rxbuf[i2cp->rxidx++] = device->dataFifo; } }
/** * @brief I2C shared ISR code. * * @param[in] i2cp pointer to the @p I2CDriver object * * @notapi */ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { I2C_TypeDef *dp = i2cp->i2c; /* Interrupts are disabled just before dmaStreamEnable() because there is no need of interrupts until next transaction begin. All the work is done by the DMA.*/ switch (i2c_get_event(i2cp)) { case I2C_EV5_MASTER_MODE_SELECT: dp->DR = i2cp->addr; break; case I2C_EV6_MASTER_REC_MODE_SELECTED: dp->CR2 &= ~I2C_CR2_ITEVTEN; dmaStreamEnable(i2cp->dmarx); dp->CR2 |= I2C_CR2_LAST; /* Needed in receiver mode. */ break; case I2C_EV6_MASTER_TRA_MODE_SELECTED: dp->CR2 &= ~I2C_CR2_ITEVTEN; dmaStreamEnable(i2cp->dmatx); break; case I2C_EV8_2_MASTER_BYTE_TRANSMITTED: /* Catches BTF event after the end of transmission.*/ if (dmaStreamGetTransactionSize(i2cp->dmarx) > 0) { /* Starts "read after write" operation, LSB = 1 -> receive.*/ i2cp->addr |= 0x01; dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK; return; } dp->CR2 &= ~I2C_CR2_ITEVTEN; dp->CR1 |= I2C_CR1_STOP; wakeup_isr(i2cp, RDY_OK); break; default: break; } }
/** * @brief DMA RX end IRQ handler. * * @param[in] nandp pointer to the @p NANDDriver object * @param[in] flags pre-shifted content of the ISR register * * @notapi */ static void nand_lld_serve_transfer_end_irq(NANDDriver *nandp, uint32_t flags) { /* DMA errors handling.*/ #if defined(STM32_NAND_DMA_ERROR_HOOK) if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { STM32_NAND_DMA_ERROR_HOOK(nandp); } #else (void)flags; #endif osalSysLockFromISR(); dmaStreamDisable(nandp->dma); switch (nandp->state){ case NAND_DMA_TX: nandp->state = NAND_PROGRAM; nandp->map_cmd[0] = NAND_CMD_PAGEPROG; /* thread will be woken from ready_isr() */ break; case NAND_DMA_RX: nandp->state = NAND_READY; nandp->rxdata = NULL; nandp->datalen = 0; wakeup_isr(nandp); break; default: osalSysHalt("Unhandled case"); break; } osalSysUnlockFromISR(); }
/** * @brief I2C shared ISR code. * * @param[in] i2cp pointer to the @p I2CDriver object * @param[in] isr content of the ISR register to be decoded * * @notapi */ static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) { I2C_TypeDef *dp = i2cp->i2c; if ((isr & I2C_ISR_TC) && (i2cp->state == I2C_ACTIVE_TX)) { size_t rxbytes; /* Make sure no more 'Transfer complete' interrupts.*/ dp->CR1 &= ~I2C_CR1_TCIE; rxbytes = dmaStreamGetTransactionSize(i2cp->dmarx); if (rxbytes > 0) { i2cp->state = I2C_ACTIVE_RX; /* Enable RX DMA */ dmaStreamEnable(i2cp->dmarx); dp->CR2 &= ~I2C_CR2_NBYTES; dp->CR2 |= rxbytes << 16; /* Starts the read operation.*/ dp->CR2 |= I2C_CR2_RD_WRN; dp->CR2 |= I2C_CR2_START; } else { /* Nothing to receive - send STOP immediately.*/ dp->CR2 |= I2C_CR2_STOP; } } if (isr & I2C_ISR_NACKF) { /* Starts a STOP sequence immediately on error.*/ dp->CR2 |= I2C_CR2_STOP; i2cp->errors |= I2CD_ACK_FAILURE; } if (isr & I2C_ISR_STOPF) { /* Stops the associated DMA streams.*/ dmaStreamDisable(i2cp->dmatx); dmaStreamDisable(i2cp->dmarx); if (i2cp->errors) { wakeup_isr(i2cp, RDY_RESET); } else { wakeup_isr(i2cp, RDY_OK); } } }
void serve_i2c_interrupt(I2CDriver *i2cp) { i2cdef_t i2c = i2cp->i2c; uint32_t status = i2c->TWI_SR; msg_t msg; if (status & TWI_SR_ENDRX) { palTogglePad(IOPORTA, 21); /* Disable PDC */ i2c->TWI_PTCR = TWI_PTCR_RXTDIS; i2c->TWI_IDR = TWI_IDR_ENDRX; /* Wait for RX ready flag */ while (1) { status = i2c->TWI_SR; if (status & TWI_SR_RXRDY) { break; } } /* Complete the transfer. */ i2c->TWI_CR = TWI_CR_STOP; /* Read second last data */ *i2cp->curbuf++ = i2c->TWI_RHR; /* Wait for RX ready flag */ while (1) { status = i2c->TWI_SR; if (status & TWI_SR_RXRDY) { break; } } /* Read last data */ *i2cp->curbuf++ = i2c->TWI_RHR; /* Wait for TX complete flag before releasing semaphore */ while (1) { status = i2c->TWI_SR; if (status & TWI_SR_TXCOMP) { break; } } msg = RDY_OK; } else if (status & (TWI_SR_NACK | TWI_SR_OVRE)) { msg = RDY_RESET; i2cp->errors = status; } wakeup_isr(i2cp, msg); }
/** * @brief I2C error handler. * * @param[in] i2cp pointer to the @p I2CDriver object * * @notapi */ static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp) { I2C_TypeDef *dp = i2cp->i2c; i2cflags_t errors; /* Clears interrupt flags just to be safe.*/ chSysLockFromIsr(); dmaStreamDisable(i2cp->dmatx); dmaStreamDisable(i2cp->dmarx); chSysUnlockFromIsr(); errors = I2CD_NO_ERROR; if (dp->SR1 & I2C_SR1_BERR) { /* Bus error. */ dp->SR1 &= ~I2C_SR1_BERR; errors |= I2CD_BUS_ERROR; } if (dp->SR1 & I2C_SR1_ARLO) { /* Arbitration lost. */ dp->SR1 &= ~I2C_SR1_ARLO; errors |= I2CD_ARBITRATION_LOST; } if (dp->SR1 & I2C_SR1_AF) { /* Acknowledge fail. */ dp->SR1 &= ~I2C_SR1_AF; dp->CR2 &= ~I2C_CR2_ITEVTEN; dp->CR1 |= I2C_CR1_STOP; /* Setting stop bit. */ errors |= I2CD_ACK_FAILURE; } if (dp->SR1 & I2C_SR1_OVR) { /* Overrun. */ dp->SR1 &= ~I2C_SR1_OVR; errors |= I2CD_OVERRUN; } if (dp->SR1 & I2C_SR1_PECERR) { /* PEC error. */ dp->SR1 &= ~I2C_SR1_PECERR; errors |= I2CD_PEC_ERROR; } if (dp->SR1 & I2C_SR1_TIMEOUT) { /* SMBus Timeout. */ dp->SR1 &= ~I2C_SR1_TIMEOUT; errors |= I2CD_TIMEOUT; } if (dp->SR1 & I2C_SR1_SMBALERT) { /* SMBus alert. */ dp->SR1 &= ~I2C_SR1_SMBALERT; errors |= I2CD_SMB_ALERT; } /* If some error has been identified then sends wakes the waiting thread.*/ if (errors != I2CD_NO_ERROR) { i2cp->errors = errors; wakeup_isr(i2cp, RDY_RESET); } }
/** * @brief DMA RX end IRQ handler. * * @param[in] i2cp pointer to the @p I2CDriver object * @param[in] flags pre-shifted content of the ISR register * * @notapi */ static void i2c_lld_serve_rx_end_irq(I2CDriver *i2cp, uint32_t flags) { I2C_TypeDef *dp = i2cp->i2c; /* DMA errors handling.*/ #if defined(STM32_I2C_DMA_ERROR_HOOK) if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { STM32_I2C_DMA_ERROR_HOOK(i2cp); } #else (void)flags; #endif dmaStreamDisable(i2cp->dmarx); dp->CR2 |= I2C_CR2_STOP; wakeup_isr(i2cp, RDY_OK); }
/** * @brief I2C error handler. * * @param[in] i2cp pointer to the @p I2CDriver object * * @notapi */ static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint32_t status) { i2cflags_t error = 0; switch (status) { case I2C_STATE_ARB_LOST: error = I2CD_ARBITRATION_LOST; break; case I2C_STATE_BUS_ERROR: error = I2CD_BUS_ERROR; break; case I2C_STATE_MS_SLAR_NACK: case I2C_STATE_MS_TDAT_NACK: case I2C_STATE_MS_SLAW_NACK: error = I2CD_ACK_FAILURE ; break; } /* If some error has been identified then sends wakes the waiting thread.*/ i2cp->errors = error; wakeup_isr(i2cp, RDY_RESET); }
/** * @brief I2C error handler. * * @param[in] i2cp pointer to the @p I2CDriver object * @param[in] isr content of the ISR register to be decoded * * @notapi */ static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint32_t isr) { /* Clears interrupt flags just to be safe.*/ dmaStreamDisable(i2cp->dmatx); dmaStreamDisable(i2cp->dmarx); if (isr & I2C_ISR_BERR) i2cp->errors |= I2CD_BUS_ERROR; if (isr & I2C_ISR_ARLO) i2cp->errors |= I2CD_ARBITRATION_LOST; if (isr & I2C_ISR_OVR) i2cp->errors |= I2CD_OVERRUN; if (isr & I2C_ISR_TIMEOUT) i2cp->errors |= I2CD_TIMEOUT; /* If some error has been identified then sends wakes the waiting thread.*/ if (i2cp->errors != I2CD_NO_ERROR) wakeup_isr(i2cp, RDY_RESET); }
/** * @brief I2C error handler. * * @param[in] i2cp pointer to the @p I2CDriver object * @param[in] sr content of the SR1 register to be decoded * * @notapi */ static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) { /* Clears interrupt flags just to be safe.*/ dmaStreamDisable(i2cp->dmatx); dmaStreamDisable(i2cp->dmarx); i2cp->errors = I2CD_NO_ERROR; if (sr & I2C_SR1_BERR) /* Bus error. */ i2cp->errors |= I2CD_BUS_ERROR; if (sr & I2C_SR1_ARLO) /* Arbitration lost. */ i2cp->errors |= I2CD_ARBITRATION_LOST; if (sr & I2C_SR1_AF) { /* Acknowledge fail. */ i2cp->i2c->CR2 &= ~I2C_CR2_ITEVTEN; i2cp->i2c->CR1 |= I2C_CR1_STOP; /* Setting stop bit. */ i2cp->errors |= I2CD_ACK_FAILURE; } if (sr & I2C_SR1_OVR) /* Overrun. */ i2cp->errors |= I2CD_OVERRUN; if (sr & I2C_SR1_TIMEOUT) /* SMBus Timeout. */ i2cp->errors |= I2CD_TIMEOUT; if (sr & I2C_SR1_PECERR) /* PEC error. */ i2cp->errors |= I2CD_PEC_ERROR; if (sr & I2C_SR1_SMBALERT) /* SMBus alert. */ i2cp->errors |= I2CD_SMB_ALERT; /* If some error has been identified then sends wakes the waiting thread.*/ if (i2cp->errors != I2CD_NO_ERROR) wakeup_isr(i2cp, RDY_RESET); }