diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/device.h b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/device.h index 8c83472d9e..53fa475078 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/device.h +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/device.h @@ -16,7 +16,8 @@ #ifndef MBED_DEVICE_H #define MBED_DEVICE_H -#define DEVICE_ID_LENGTH 32 +#define DEVICE_ID_LENGTH 32 +#define TRANSACTION_QUEUE_SIZE_SPI 4 #include "objects.h" diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/i2c_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/i2c_api.c index 1fe9cc851c..66dd86332b 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/i2c_api.c +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/i2c_api.c @@ -21,6 +21,12 @@ #include "pinmap.h" #include "gpio_include.h" +#if DEVICE_I2C_ASYNCH +#define I2C_S(obj) (struct i2c_s *) (&((obj)->i2c)) +#else +#define I2C_S(obj) (struct i2c_s *) (obj) +#endif + static const PinMap PinMap_I2C_SDA[] = { {PC1, I2C_0, PIN_DATA(1, 2)}, {PA5, I2C_1, PIN_DATA(1, 2)}, @@ -49,40 +55,84 @@ static const uint32_t I2C_SCK_DIVIDER_TBL[8] = { I2C_clock_setting_t clk; static uint32_t start_flag = 0; +#if DEVICE_I2C_ASYNCH +enum { + I2C_TRANSFER_STATE_IDLE = 0U, + I2C_TRANSFER_STATE_START, + I2C_TRANSFER_STATE_WRITE, + I2C_TRANSFER_STATE_RESTART, + I2C_TRANSFER_STATE_READ, + I2C_TRANSFER_STATE_MAX +} TransferState; + +typedef struct { + IRQn_Type i2c; +} i2c_irq_t; + +static const i2c_irq_t I2C_CH0_IRQN_TBL[1] = { + {INTI2C0_IRQn} +}; + +static const i2c_irq_t I2C_CH1_IRQN_TBL[1] = { + {INTI2C1_IRQn} +}; + +static const i2c_irq_t I2C_CH2_IRQN_TBL[1] = { + {INTI2C2_IRQn} +}; +#endif + static int32_t wait_status(i2c_t *p_obj); static void i2c_start_bit(i2c_t *obj); +#if DEVICE_I2C_ASYNCH +static void disable_irq(uint32_t irqn); +static void clear_irq(uint32_t irqn); +static void i2c_irq_handler(i2c_t *obj); +#endif + // Initialize the I2C peripheral. It sets the default parameters for I2C void i2c_init(i2c_t *obj, PinName sda, PinName scl) { - MBED_ASSERT(obj != NULL); - + struct i2c_s *obj_s = I2C_S(obj); + MBED_ASSERT(obj_s != NULL); I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA); I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL); I2CName i2c_name = (I2CName)pinmap_merge(i2c_sda, i2c_scl); - MBED_ASSERT((int)i2c_name != NC); switch (i2c_name) { case I2C_0: TSB_CG_FSYSENA_IPENA20 = ENABLE; TSB_CG_FSYSENA_IPENA02 = ENABLE; - obj->i2c = TSB_I2C0; + obj_s->i2c = TSB_I2C0; +#if DEVICE_I2C_ASYNCH + obj_s->irqn = (uint32_t)&I2C_CH0_IRQN_TBL; +#endif break; case I2C_1: TSB_CG_FSYSENA_IPENA21 = ENABLE; TSB_CG_FSYSENA_IPENA00 = ENABLE; - obj->i2c = TSB_I2C1; + obj_s->i2c = TSB_I2C1; +#if DEVICE_I2C_ASYNCH + obj_s->irqn = (uint32_t)&I2C_CH1_IRQN_TBL; +#endif break; case I2C_2: TSB_CG_FSYSENA_IPENA22 = ENABLE; TSB_CG_FSYSENA_IPENA10 = ENABLE; - obj->i2c = TSB_I2C2; + obj_s->i2c = TSB_I2C2; +#if DEVICE_I2C_ASYNCH + obj_s->irqn = (uint32_t)&I2C_CH2_IRQN_TBL; +#endif break; default: error("I2C is not available"); break; } +#if DEVICE_I2C_ASYNCH + obj_s->state = I2C_TRANSFER_STATE_IDLE; +#endif pinmap_pinout(sda, PinMap_I2C_SDA); pin_mode(sda, OpenDrain); @@ -94,15 +144,16 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl) i2c_reset(obj); i2c_frequency(obj, 100000); - obj->i2c->CR2 = (I2CxCR2_I2CM_ENABLE | I2CxCR2_TRX | I2CxCR2_PIN_CLEAR | - I2CxCR2_INIT); - obj->i2c->OP = I2CxOP_INIT; - obj->i2c->IE = I2CxIE_CLEAR; + obj_s->i2c->CR2 = (I2CxCR2_I2CM_ENABLE | I2CxCR2_TRX | I2CxCR2_PIN_CLEAR | + I2CxCR2_INIT); + obj_s->i2c->OP = I2CxOP_INIT; + obj_s->i2c->IE = I2CxIE_CLEAR; } // Configure the I2C frequency void i2c_frequency(i2c_t *obj, int hz) { + struct i2c_s *obj_s = I2C_S(obj); uint64_t sck; uint64_t tmp_sck; uint64_t prsck; @@ -134,8 +185,8 @@ void i2c_frequency(i2c_t *obj, int hz) clk.prsck = (tmp_prsck < 32) ? (uint32_t)(tmp_prsck - 1) : 0; } - obj->i2c->CR1 = (I2CxCR1_ACK | clk.sck); - obj->i2c->PRS = (I2CxPRS_PRCK & clk.prsck); + obj_s->i2c->CR1 = (I2CxCR1_ACK | clk.sck); + obj_s->i2c->PRS = (I2CxPRS_PRCK & clk.prsck); } int i2c_start(i2c_t *obj) @@ -146,11 +197,12 @@ int i2c_start(i2c_t *obj) int i2c_stop(i2c_t *obj) { + struct i2c_s *obj_s = I2C_S(obj); uint32_t timeout = I2C_TIMEOUT; - obj->i2c->CR2 = I2CxCR2_STOP_CONDITION; + obj_s->i2c->CR2 = I2CxCR2_STOP_CONDITION; - while ((obj->i2c->SR & I2CxSR_BB) == I2CxSR_BB) { + while ((obj_s->i2c->SR & I2CxSR_BB) == I2CxSR_BB) { if (timeout == 0) { break; } @@ -162,8 +214,9 @@ int i2c_stop(i2c_t *obj) void i2c_reset(i2c_t *obj) { - obj->i2c->CR2 = I2CxCR2_SWRES_10; - obj->i2c->CR2 = I2CxCR2_SWRES_01; + struct i2c_s *obj_s = I2C_S(obj); + obj_s->i2c->CR2 = I2CxCR2_SWRES_10; + obj_s->i2c->CR2 = I2CxCR2_SWRES_01; } int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) @@ -224,22 +277,23 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) int i2c_byte_read(i2c_t *obj, int last) { + struct i2c_s *obj_s = I2C_S(obj); int32_t result = 0; - obj->i2c->ST = I2CxST_CLEAR; + obj_s->i2c->ST = I2CxST_CLEAR; if (last) { - obj->i2c->OP |= I2CxOP_MFACK; + obj_s->i2c->OP |= I2CxOP_MFACK; } else { - obj->i2c->OP &= ~I2CxOP_MFACK; + obj_s->i2c->OP &= ~I2CxOP_MFACK; } - obj->i2c->DBR = (0 & I2CxDBR_DB_MASK); + obj_s->i2c->DBR = (0 & I2CxDBR_DB_MASK); if (wait_status(obj) < 0) { result = -1; } else { - result = (int32_t)(obj->i2c->DBR & I2CxDBR_DB_MASK); + result = (int32_t)(obj_s->i2c->DBR & I2CxDBR_DB_MASK); } return result; @@ -247,22 +301,23 @@ int i2c_byte_read(i2c_t *obj, int last) int i2c_byte_write(i2c_t *obj, int data) { + struct i2c_s *obj_s = I2C_S(obj); int32_t result = 0; - obj->i2c->ST = I2CxST_CLEAR; + obj_s->i2c->ST = I2CxST_CLEAR; if (start_flag == 1) { - obj->i2c->DBR = (data & I2CxDBR_DB_MASK); + obj_s->i2c->DBR = (data & I2CxDBR_DB_MASK); i2c_start_bit(obj); start_flag = 0; } else { - obj->i2c->DBR = (data & I2CxDBR_DB_MASK); + obj_s->i2c->DBR = (data & I2CxDBR_DB_MASK); } if (wait_status(obj) < 0) { return -1; } - if (!((obj->i2c->SR & I2CxSR_LRB) == I2CxSR_LRB)) { + if (!((obj_s->i2c->SR & I2CxSR_LRB) == I2CxSR_LRB)) { result = 1; } else { result = 0; @@ -273,25 +328,27 @@ int i2c_byte_write(i2c_t *obj, int data) static void i2c_start_bit(i2c_t *obj) // Send START command { + struct i2c_s *obj_s = I2C_S(obj); uint32_t opreg = 0; - opreg = obj->i2c->OP; + opreg = obj_s->i2c->OP; opreg &= ~(I2CxOP_RSTA | I2CxOP_SREN); - if ((obj->i2c->SR & I2CxSR_BB)) { + if ((obj_s->i2c->SR & I2CxSR_BB)) { opreg |= I2CxOP_SREN; } - obj->i2c->OP = opreg; - obj->i2c->CR2 |= I2CxCR2_START_CONDITION; + obj_s->i2c->OP = opreg; + obj_s->i2c->CR2 |= I2CxCR2_START_CONDITION; } static int32_t wait_status(i2c_t *p_obj) { + struct i2c_s *obj_s = I2C_S(p_obj); volatile int32_t timeout; timeout = I2C_TIMEOUT; - while (!((p_obj->i2c->ST & I2CxST_I2C) == I2CxST_I2C)) { + while (!((obj_s->i2c->ST & I2CxST_I2C) == I2CxST_I2C)) { if ((timeout--) == 0) { return (-1); } @@ -302,32 +359,38 @@ static int32_t wait_status(i2c_t *p_obj) void i2c_slave_mode(i2c_t *obj, int enable_slave) { + struct i2c_s *obj_s = I2C_S(obj); if (enable_slave) { - obj->i2c->OP = I2CxOP_SLAVE_INIT; - obj->i2c->CR1 = (I2CxCR1_ACK | clk.sck); - obj->i2c->CR2 = (I2CxCR2_INIT | I2CxCR2_PIN_CLEAR); - obj->i2c->PRS = (I2CxPRS_PRCK & clk.prsck); - obj->i2c->AR = (obj->address & I2CAR_SA_MASK); - obj->i2c->IE = I2CxIE_INTI2C; + i2c_reset(obj); + obj_s->i2c->OP = I2CxOP_SLAVE_INIT; + obj_s->i2c->CR1 = (I2CxCR1_ACK | clk.sck); + obj_s->i2c->CR2 = (I2CxCR2_INIT | I2CxCR2_PIN_CLEAR); + obj_s->i2c->CR2 = I2CxCR2_INIT; + obj_s->i2c->PRS = (I2CxPRS_PRCK & clk.prsck); + obj_s->i2c->AR = (obj_s->address & I2CAR_SA_MASK); + obj_s->i2c->IE = I2CxIE_INTI2C; } else { i2c_reset(obj); - obj->i2c->CR2 = (I2CxCR2_I2CM_ENABLE | I2CxCR2_TRX | I2CxCR2_PIN_CLEAR | - I2CxCR2_INIT); - obj->i2c->OP = I2CxOP_INIT; - obj->i2c->CR1 = (I2CxCR1_ACK | clk.sck); - obj->i2c->PRS = (I2CxPRS_PRCK & clk.prsck); - NVIC_DisableIRQ(obj->IRQn); - NVIC_ClearPendingIRQ(obj->IRQn); - obj->i2c->ST = I2CxST_CLEAR; + obj_s->i2c->CR2 = (I2CxCR2_I2CM_ENABLE | I2CxCR2_TRX | I2CxCR2_PIN_CLEAR | + I2CxCR2_INIT); + obj_s->i2c->OP = I2CxOP_INIT; + obj_s->i2c->CR1 = (I2CxCR1_ACK | clk.sck); + obj_s->i2c->PRS = (I2CxPRS_PRCK & clk.prsck); + obj_s->i2c->ST = I2CxST_CLEAR; } } int i2c_slave_receive(i2c_t *obj) { + struct i2c_s *obj_s = I2C_S(obj); int32_t result = I2C_NO_DATA; - if ((obj->i2c->ST & I2CxST_I2C) && (obj->i2c->OP & I2CxOP_SAST)) { - if ((obj->i2c->SR & I2CxSR_TRX) == I2CxSR_TRX) { + if ((obj_s->i2c->ST & I2CxST_I2C) && (obj_s->i2c->OP & I2CxOP_SAST)) { + // Detect and clear arbitration lost. + if(!(obj_s->i2c->SR & 0x08)) { + obj_s->i2c->DBR = 0x00; + } + if ((obj_s->i2c->SR & I2CxSR_TRX) == I2CxSR_TRX) { result = I2C_READ_ADDRESSED; } else { result = I2C_WRITE_ADDRESSED; @@ -339,11 +402,12 @@ int i2c_slave_receive(i2c_t *obj) int i2c_slave_read(i2c_t *obj, char *data, int length) { + struct i2c_s *obj_s = I2C_S(obj); int32_t count = 0; while (count < length) { - int32_t pdata = i2c_byte_read(obj, ((count < (length - 1)) ? 0 : 1)); - if ((obj->i2c->SR & I2CxSR_TRX)) { + int32_t pdata = i2c_byte_read(obj, 0); + if ((obj_s->i2c->SR & I2CxSR_TRX)) { return (count); } else { if (pdata < 0) { @@ -375,7 +439,8 @@ int i2c_slave_write(i2c_t *obj, const char *data, int length) void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) { - obj->address = address & I2CAR_SA_MASK; + struct i2c_s *obj_s = I2C_S(obj); + obj_s->address = address & I2CAR_SA_MASK; i2c_slave_mode(obj,1); } @@ -399,4 +464,210 @@ const PinMap *i2c_slave_scl_pinmap() return PinMap_I2C_SCL; } +#if DEVICE_I2C_ASYNCH + +void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint32_t address, + uint32_t stop, uint32_t handler, uint32_t event, DMAUsage hint) +{ + struct i2c_s *obj_s = I2C_S(obj); + i2c_irq_t *p_irqn = (i2c_irq_t *)obj_s->irqn; + + if(obj_s->state == I2C_TRANSFER_STATE_IDLE) { + // Disable and clear interrupt flag. + disable_irq(obj_s->irqn); + obj_s->i2c->IE = I2CxIE_CLEAR; + obj_s->i2c->ST = I2CxST_CLEAR; + clear_irq(obj_s->irqn); + + // Store given buffer data and lenght into I2C object and set state as I2C_TRANSFER_STATE_START. + obj_s->address = address; + obj_s->event = 0; + obj_s->stop = stop; + obj->tx_buff.buffer = (void *)tx; + obj->tx_buff.length = tx_length; + obj->tx_buff.pos = 0; + obj->rx_buff.buffer = rx; + obj->rx_buff.length = rx_length; + obj->rx_buff.pos = 0; + obj_s->state = I2C_TRANSFER_STATE_START; + + // Enable I2C interrupt. + obj_s->i2c->IE = I2CxIE_INTI2C; + + if ((tx_length == 0) && (rx_length != 0)) { + i2c_start_bit(obj); + obj_s->i2c->DBR = ((address | 1U) & I2CxDBR_DB_MASK); + } else { + i2c_start_bit(obj); + obj_s->i2c->DBR = (address & I2CxDBR_DB_MASK); + } + + // Enable I2C interrupr in NVIC. + NVIC_EnableIRQ(p_irqn->i2c); + NVIC_SetVector(p_irqn->i2c, handler); + } +} + +uint32_t i2c_irq_handler_asynch(i2c_t *obj) +{ + struct i2c_s *obj_s = I2C_S(obj); + i2c_irq_handler(obj); + return (obj_s->event & I2C_EVENT_ALL); +} + +uint8_t i2c_active(i2c_t *obj) +{ + struct i2c_s *obj_s = I2C_S(obj); + uint8_t ret_val = 0; + + if ((obj_s->i2c->CR2 & 0x08)) { + ret_val = 1; + } + return ret_val; +} + +void i2c_abort_asynch(i2c_t *obj) +{ + struct i2c_s *obj_s = I2C_S(obj); + + // Generate Stop condition on I2C bus + i2c_stop(obj); + + // Set state as idle and disable I2C interrupt. + obj_s->state = I2C_TRANSFER_STATE_IDLE; + disable_irq(obj_s->irqn); + clear_irq(obj_s->irqn); + obj_s->i2c->IE = I2CxIE_CLEAR; + + // Given I2C Software Reset + i2c_reset(obj); + + // Re-Store the I2C configuration + obj_s->i2c->CR2 = (I2CxCR2_I2CM_ENABLE | I2CxCR2_TRX | I2CxCR2_PIN_CLEAR | I2CxCR2_INIT); + obj_s->i2c->OP = I2CxOP_INIT; + obj_s->i2c->CR1 = (I2CxCR1_ACK | clk.sck); + obj_s->i2c->PRS = (I2CxPRS_PRCK & clk.prsck); + obj_s->i2c->ST = I2CxST_CLEAR; + +} + +static void disable_irq(uint32_t irqn) +{ + i2c_irq_t *p_irqn = (i2c_irq_t *)irqn; + NVIC_DisableIRQ(p_irqn->i2c); +} + +static void clear_irq(uint32_t irqn) +{ + i2c_irq_t *p_irqn = (i2c_irq_t *)irqn; + NVIC_ClearPendingIRQ(p_irqn->i2c); +} + +static void i2c_irq_handler(i2c_t *obj) +{ + struct i2c_s *obj_s = I2C_S(obj); + obj_s->i2c->ST = I2CxST_CLEAR; + + switch(obj_s->state) { + case I2C_TRANSFER_STATE_START: + // Check ACK for sent slave address. + if (!((obj_s->i2c->SR & I2CxSR_LRB) == I2CxSR_LRB)) { + + if(obj->tx_buff.length != (unsigned long)0) { // Check Tx buff length. + obj_s->i2c->DBR = *((uint8_t *)obj->tx_buff.buffer)& I2CxDBR_DB_MASK; + obj->tx_buff.buffer = (uint8_t *)obj->tx_buff.buffer + sizeof(uint8_t); + obj->tx_buff.pos++; + obj_s->state = I2C_TRANSFER_STATE_WRITE; + } else if(obj->rx_buff.length != 0) { // Check Rx buff length. + if ((obj->rx_buff.pos < (obj->rx_buff.length - 1))) { + obj_s->i2c->OP &= ~I2CxOP_MFACK; + } else { + obj_s->i2c->OP |= I2CxOP_MFACK; + } + obj_s->i2c->DBR = 0x00; + obj_s->state = I2C_TRANSFER_STATE_READ; + } else { // Return transfer complete because of not given any Tx/Rx data. + obj_s->event = I2C_EVENT_TRANSFER_COMPLETE; + obj_s->state = I2C_TRANSFER_STATE_IDLE; + } + } else { // Return "No Slave", Because of Did not get any ACK for sent slave address. + obj_s->event = (I2C_EVENT_ERROR | I2C_EVENT_ERROR_NO_SLAVE); + obj_s->state = I2C_TRANSFER_STATE_IDLE; + } + break; + case I2C_TRANSFER_STATE_WRITE: + if(obj->tx_buff.pos < obj->tx_buff.length) { + if (!((obj_s->i2c->SR & I2CxSR_LRB) == I2CxSR_LRB)) { + obj_s->i2c->DBR = *((uint8_t *)obj->tx_buff.buffer)& I2CxDBR_DB_MASK; + obj->tx_buff.buffer = (uint8_t *)obj->tx_buff.buffer + sizeof(uint8_t); + obj->tx_buff.pos++; + } else { + obj_s->event = (I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_EARLY_NACK); + obj_s->state = I2C_TRANSFER_STATE_IDLE; + } + } else if(obj->rx_buff.length != 0) { + if (!((obj_s->i2c->SR & I2CxSR_LRB) == I2CxSR_LRB)) { + i2c_start_bit(obj); + obj_s->i2c->DBR = ((obj_s->address | 1U) & I2CxDBR_DB_MASK); + obj_s->state = I2C_TRANSFER_STATE_RESTART; + } else { + obj_s->event = (I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_EARLY_NACK); + obj_s->state = I2C_TRANSFER_STATE_IDLE; + } + } else { + if(obj_s->stop) { + obj_s->i2c->CR2 = I2CxCR2_STOP_CONDITION; + } + obj_s->event = I2C_EVENT_TRANSFER_COMPLETE; + obj_s->state = I2C_TRANSFER_STATE_IDLE; + } + break; + case I2C_TRANSFER_STATE_RESTART: + if(!((obj_s->i2c->SR & I2CxSR_LRB) == I2CxSR_LRB)) { + // Set ACK/NACK + if ((obj->rx_buff.pos < (obj->rx_buff.length - 1))) { + obj_s->i2c->OP &= ~I2CxOP_MFACK; + } else { + obj_s->i2c->OP |= I2CxOP_MFACK; + } + obj_s->i2c->DBR = 0x00; + obj_s->state = I2C_TRANSFER_STATE_READ; + } else { + obj_s->event = (I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_EARLY_NACK); + obj_s->state = I2C_TRANSFER_STATE_IDLE; + } + break; + case I2C_TRANSFER_STATE_READ: + if(obj->rx_buff.pos < obj->rx_buff.length) { + *((uint8_t *)obj->rx_buff.buffer) = (uint8_t)obj_s->i2c->DBR & I2CxDBR_DB_MASK; + obj->rx_buff.buffer = (uint8_t *)obj->rx_buff.buffer + sizeof(uint8_t); + obj->rx_buff.pos++; + } + if(obj->rx_buff.pos < obj->rx_buff.length) { + // Set ACK/NACK + if ((obj->rx_buff.pos < (obj->rx_buff.length - 1))) { + obj_s->i2c->OP &= ~I2CxOP_MFACK; + } else { + obj_s->i2c->OP |= I2CxOP_MFACK; + } + obj_s->i2c->DBR = 0x00; + } else { + if(obj_s->stop) { + obj_s->i2c->CR2 = I2CxCR2_STOP_CONDITION; + } + obj_s->event = I2C_EVENT_TRANSFER_COMPLETE; + obj_s->state = I2C_TRANSFER_STATE_IDLE; + } + break; + default: + break; + } + if(obj_s->state == I2C_TRANSFER_STATE_IDLE) { + disable_irq(obj_s->irqn); + obj_s->i2c->IE = I2CxIE_CLEAR; + } +} + +#endif // #if DEVICE_I2C_ASYNCH + #endif // #if DEVICE_I2C diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/objects.h b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/objects.h index 4f5e625464..a02e801149 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/objects.h +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/objects.h @@ -93,14 +93,26 @@ struct pwmout_s { struct i2c_s { uint32_t address; - IRQn_Type IRQn; - TSB_I2C_TypeDef *i2c; + TSB_I2C_TypeDef *i2c; +#if DEVICE_I2C_ASYNCH + uint32_t irqn; + uint32_t state; + uint32_t event; + uint32_t stop; +#endif }; struct spi_s { - tspi_t p_obj; - SPIName module; - uint8_t bits; + tspi_t p_obj; + SPIName module; + uint8_t bits; + PinName Slave_SCK; +#if DEVICE_SPI_ASYNCH + uint32_t irqn; + uint32_t event; + uint32_t max_size; + uint32_t state; +#endif }; extern const gpio_regtypedef_t GPIO_SFRs[]; diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/rtc_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/rtc_api.c new file mode 100644 index 0000000000..f52749bb9c --- /dev/null +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/rtc_api.c @@ -0,0 +1,218 @@ +/* mbed Microcontroller Library + * (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2018 All rights reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rtc_api.h" +#include "mbed_mktime.h" + +#define RTC_24_HOUR_MODE ((uint8_t)0x01) +#define PAGER_PAGE_ONE ((uint8_t)0x01) +#define PAGER_PAGE_ZERO ((uint8_t)0xEE) +#define RTC_CLK_ENABLE ((uint8_t)0x08) +#define RTC_CLK_DISABLE ((uint8_t)0xE7) +#define RTCRESTR_RSTTMR_MASK ((uint8_t)0x20) +#define RTCRESTR_RSTTMR_R_RUN ((uint8_t)0x20) +#define CGWUPLCR_WUPTL_HIGH_MASK ((uint32_t)0x07FFF000) +#define CGWUPLCR_WULEF_MASK ((uint32_t)0x00000002) +#define CGWUPLCR_WULEF_R_DONE ((uint32_t)0x00000000) +#define CGWUPLCR_WULON_W_ENABLE ((uint32_t)0x00000001) +#define RLMLOSCCR_XTEN_RW_ENABLE ((uint32_t)0x00000001) +#define ELOSC_CFG_WARM_UP_TIME ((uint64_t)(5000)) +#define ELOSC_CFG_CLOCK ((uint64_t)(32768)) +#define HEX2DEC(val) ((val >> 4U) * 10U + val % 16U) // Hex to Dec conversion macro +#define DEC2HEX(val) ((val / 10U) * 16U + val % 10U) // Dec to Hex conversion macro + +static int flag = 0; +static int diff_year = 100; //our RTC register only support 2000~2099 +static void external_losc_enable(void); + +void rtc_init(void) +{ + if (!flag) { + TSB_CG_FSYSENB_IPENB03 = 1; // Enable Sys Clock for RTC + external_losc_enable(); // Enable low-speed oscillator + TSB_RTC->PAGER = 0x00; //disable clock and alarm + + while ((TSB_RTC->RESTR & RTCRESTR_RSTTMR_MASK) == RTCRESTR_RSTTMR_R_RUN) { + // Reset RTC sec counter + } + + TSB_RTC->RESTR = 0xE7; + while ((TSB_RTC->RESTR & RTCRESTR_RSTTMR_MASK) == RTCRESTR_RSTTMR_R_RUN) { + // Reset RTC sec counter + } + + TSB_RTC->PAGER |= PAGER_PAGE_ONE; + TSB_RTC->YEARR = 0x03; // Set leap year state + TSB_RTC->MONTHR = RTC_24_HOUR_MODE; // Set hour mode + TSB_RTC->PAGER &= PAGER_PAGE_ZERO; // Set hour mode + TSB_RTC->YEARR = 0x01; // Set year value + TSB_RTC->MONTHR = (uint8_t)0x01; // Set month value + TSB_RTC->DATER = (uint8_t)0x01; // Set date value + TSB_RTC->DAYR = (uint8_t)0x0; // Set day value + TSB_RTC->HOURR = (uint8_t)0x01; // Set hour value + TSB_RTC->MINR = (uint8_t)0x02; // Set minute value + TSB_RTC->SECR = (uint8_t)0x22; // Set second value + TSB_RTC->PAGER |= RTC_CLK_ENABLE; // Enable Clock + flag = 1; // Enable internal flag + } +} + +void rtc_free(void) +{ + if (flag) { // Check status of RTC peripheral driver is ENABLE or DISABLE + flag = 0; // Set status of RTC peripheral driver is DISABLE + } +} + +int rtc_isenabled(void) +{ + return flag; // Return a flag that represents status of RTC peripheral driver +} + +time_t rtc_read(void) +{ + struct tm timeinfo; + uint8_t read_1 = 0U; + uint8_t read_2 = 0U; + + timeinfo.tm_isdst = 0;//no summer time + + TSB_RTC->PAGER &= PAGER_PAGE_ZERO; + + read_1 = TSB_RTC->SECR; // Get sec value + timeinfo.tm_sec = HEX2DEC(read_1); + + do { // Get minute value + read_1 = TSB_RTC->MINR; + read_2 = TSB_RTC->MINR; + } while (read_1 != read_2); + timeinfo.tm_min = HEX2DEC(read_1); + + do { // Get hour value + read_1 = TSB_RTC->HOURR; + read_2 = TSB_RTC->HOURR; + } while (read_1 != read_2); + timeinfo.tm_hour = HEX2DEC(read_1); + + do { // Get Month date value + read_1 = TSB_RTC->DATER; + read_2 = TSB_RTC->DATER; + } while (read_1 != read_2); + timeinfo.tm_mday = HEX2DEC(read_1); + + do { // Get Month value + read_1 = TSB_RTC->MONTHR; + read_2 = TSB_RTC->MONTHR; + } while (read_1 != read_2); + timeinfo.tm_mon = HEX2DEC(read_1)-1; + + do { // Get weekday value + read_1 = TSB_RTC->DAYR; + read_2 = TSB_RTC->DAYR; + } while (read_1 != read_2); + timeinfo.tm_wday = HEX2DEC(read_1); + + do { // Get year value + read_1 = TSB_RTC->YEARR; + read_2 = TSB_RTC->YEARR; + } while (read_1 != read_2); + timeinfo.tm_year = (HEX2DEC(read_1)+ diff_year); + + time_t t; + + if (_rtc_maketime(&timeinfo, &t, RTC_4_YEAR_LEAP_YEAR_SUPPORT) == false) { + return 0; + } + return t; +} + +void rtc_write(time_t t) +{ + struct tm timeinfo; + if (_rtc_localtime(t, &timeinfo, RTC_4_YEAR_LEAP_YEAR_SUPPORT) == false) { + return; + } + + diff_year = timeinfo.tm_year - (timeinfo.tm_year % 100); + TSB_RTC->PAGER &= RTC_CLK_DISABLE; // Disable clock + + // Check current year is leap year or not + if (((timeinfo.tm_year % 4) == 0 && (timeinfo.tm_year % 100) != 0) || + (timeinfo.tm_year % 400) == 0) { + TSB_RTC->PAGER |= PAGER_PAGE_ONE; // Current year is a leap year + TSB_RTC->YEARR = 0x00; + } else if ((timeinfo.tm_year % 4) == 1) { + TSB_RTC->PAGER |= PAGER_PAGE_ONE; // Current year is the year following a leap year + TSB_RTC->YEARR = 0x01; + } else if ((timeinfo.tm_year % 4) == 2) { + TSB_RTC->PAGER |= PAGER_PAGE_ONE; // Current year is two years after a leap year + TSB_RTC->YEARR = 0x02; + } else { + TSB_RTC->PAGER |= PAGER_PAGE_ONE; // Current year is three years after a leap year + TSB_RTC->YEARR = 0x03; + } + + TSB_RTC->PAGER &= PAGER_PAGE_ZERO; // Select PAGE 0 + + TSB_RTC->YEARR = (uint8_t)DEC2HEX((timeinfo.tm_year - diff_year)); // Set year value + // Set month value, tm_mon=0 means Jan while 1 is Jan + TSB_RTC->MONTHR = (uint8_t)DEC2HEX((timeinfo.tm_mon+1)); + TSB_RTC->DATER = (uint8_t)DEC2HEX(timeinfo.tm_mday); // Set date value + TSB_RTC->DAYR = (uint8_t)(timeinfo.tm_wday); // Set week day value + TSB_RTC->HOURR = (uint8_t)DEC2HEX(timeinfo.tm_hour); // Set hour value + TSB_RTC->MINR = (uint8_t)DEC2HEX(timeinfo.tm_min); // Set minute value + TSB_RTC->SECR = (uint8_t)DEC2HEX(timeinfo.tm_sec); // Set second value + + TSB_RTC->RESTR |= RTCRESTR_RSTTMR_R_RUN; + while ((TSB_RTC->RESTR & RTCRESTR_RSTTMR_MASK) == RTCRESTR_RSTTMR_R_RUN) { + // Reset RTC sec counter, otherwise the 1st second will not be accurate + } + + // Setting Wait + // When stop mode is selected, CaseA or CaseB is need. + // CaseA: Wait for RTC 1Hz interrupt. + // CaseB: Check the clock register setting. + { + uint8_t flag = 1; + time_t time_read = {0}; + while(flag) { + time_read = rtc_read(); + if( time_read == t) { // Wait for setting successfully + flag = 0; + } + } + } + TSB_RTC->PAGER |= RTC_CLK_ENABLE; // Enable Clock +} + +static void external_losc_enable(void) +{ + uint32_t work; + if( (TSB_RLM->LOSCCR & 0x01) == 0 ) { //external losc is not enabled. + uint64_t x = (uint64_t)(ELOSC_CFG_WARM_UP_TIME * ELOSC_CFG_CLOCK); + x = (uint64_t)(x / (uint64_t)(1000000)); + work = (uint32_t)x; + work &= (uint32_t)(0xFFFFFFF0); + work <<= 8; + TSB_CG->WUPLCR = work; + TSB_RLM->LOSCCR = RLMLOSCCR_XTEN_RW_ENABLE; + work = (uint32_t)(TSB_CG->WUPLCR & CGWUPLCR_WUPTL_HIGH_MASK); + TSB_CG->WUPLCR = (uint32_t)(work | CGWUPLCR_WULON_W_ENABLE); + while ((TSB_CG->WUPLCR & CGWUPLCR_WULEF_MASK) != CGWUPLCR_WULEF_R_DONE) { + // No processing + } + } +} diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/serial_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/serial_api.c index 4d30ee01b3..148349dc40 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/serial_api.c +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/serial_api.c @@ -21,19 +21,35 @@ #include "objects.h" static const PinMap PinMap_UART_TX[] = { - {PA1, SERIAL_0, PIN_DATA(1, 1)}, + {PM1, SERIAL_0, PIN_DATA(1, 1)}, {PJ2, SERIAL_1, PIN_DATA(2, 1)}, - {PL1, SERIAL_2, PIN_DATA(2, 1)}, + {PB2, SERIAL_2, PIN_DATA(1, 1)}, {NC, NC, 0} }; static const PinMap PinMap_UART_RX[] = { - {PA2, SERIAL_0, PIN_DATA(1, 0)}, + {PM2, SERIAL_0, PIN_DATA(1, 0)}, {PJ1, SERIAL_1, PIN_DATA(2, 0)}, - {PL0, SERIAL_2, PIN_DATA(2, 0)}, + {PB3, SERIAL_2, PIN_DATA(1, 0)}, {NC, NC, 0} }; +#if DEVICE_SERIAL_FC +static const PinMap PinMap_UART_CTS[] = { + {PM3, SERIAL_0, PIN_DATA(1, 0)}, + {PJ3, SERIAL_1, PIN_DATA(1, 0)}, + {PB4, SERIAL_2, PIN_DATA(1, 0)}, + {NC, NC, 0} +}; + +static const PinMap PinMap_UART_RTS[] = { + {PM4, SERIAL_0, PIN_DATA(1, 1)}, + {PJ4, SERIAL_1, PIN_DATA(1, 1)}, + {PB5, SERIAL_2, PIN_DATA(1, 1)}, + {NC, NC, 0} +}; +#endif + static uint32_t serial_irq_ids[UART_NUM] = {0}; static uart_irq_handler irq_handler; int stdio_uart_inited = 0; @@ -56,7 +72,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) case SERIAL_0: obj->UARTx = TSB_UART0; TSB_CG_FSYSENA_IPENA23 = ENABLE; - TSB_CG_FSYSENA_IPENA00 = ENABLE; + TSB_CG_FSYSENA_IPENA11 = ENABLE; break; case SERIAL_1: obj->UARTx = TSB_UART1; @@ -67,7 +83,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) case SERIAL_2: obj->UARTx = TSB_UART2; TSB_CG_FSYSENA_IPENA25 = ENABLE; - TSB_CG_FSYSENA_IPENA10 = ENABLE; + TSB_CG_FSYSENA_IPENA01 = ENABLE; break; default: error("UART is not available"); @@ -290,6 +306,23 @@ void serial_break_clear(serial_t *obj) obj->UARTx->TRANS &= ~(0x08); } +#if DEVICE_SERIAL_FC +void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow) +{ + UARTName uart_cts = (UARTName)pinmap_peripheral(txflow, PinMap_UART_CTS); + UARTName uart_rts = (UARTName)pinmap_peripheral(rxflow, PinMap_UART_RTS); + UARTName uart_name = (UARTName)pinmap_merge(uart_cts, uart_rts); + MBED_ASSERT((int)uart_name != NC); + + pinmap_pinout(rxflow, PinMap_UART_RTS); + pinmap_pinout(txflow, PinMap_UART_CTS); + pin_mode(txflow, PullUp); + pin_mode(rxflow, PullUp); + + obj->UARTx->CR0 |= (3U << 9); +} +#endif + static void uart_swreset(TSB_UART_TypeDef *UARTx) { while (((UARTx->SWRST) & UARTxSWRST_SWRSTF_MASK) == UARTxSWRST_SWRSTF_RUN) { diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/spi_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/spi_api.c index ededf69ece..e18eeacb0b 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/spi_api.c +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM3H6/spi_api.c @@ -13,15 +13,50 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include "spi_api.h" #include "mbed_error.h" #include "pinmap.h" #include "gpio_include.h" #include "txz_tspi.h" +#define TIMEOUT 1000 +#define INITIAL_SPI_FREQ 1000000 + +#if DEVICE_I2C_ASYNCH +#define SPI_S(obj) (struct spi_s *) (&((obj)->spi)) +#else +#define SPI_S(obj) (struct spi_s *) (obj) +#endif + +#if DEVICE_SPI_ASYNCH +static void spi_irq_handler(spi_t *obj); +static void disable_irq(uint32_t irqn); +static void clear_irq(uint32_t irqn); + +enum { + SPI_TRANSFER_STATE_IDLE = 0U, + SPI_TRANSFER_STATE_BUSY +} SPI_TransferState; + +typedef struct { + IRQn_Type Tx; + IRQn_Type Rx; + IRQn_Type Error; +} spi_irq_t; + +static const spi_irq_t SPI_CH0_IRQN_TBL[1] = { + {INTT0RX_IRQn, INTT0TX_IRQn, INTT0ERR_IRQn} +}; + +static const spi_irq_t SPI_CH1_IRQN_TBL[1] = { + {INTT1RX_IRQn, INTT1TX_IRQn, INTT1ERR_IRQn} +}; +#endif + static const PinMap PinMap_SPI_SCLK[] = { - {PM0, SPI_0, PIN_DATA(3, 2)}, - {PP0, SPI_1, PIN_DATA(1, 2)}, + {PM0, SPI_0, PIN_DATA(3, 1)}, + {PP0, SPI_1, PIN_DATA(1, 1)}, {NC, NC, 0} }; @@ -38,13 +73,20 @@ static const PinMap PinMap_SPI_MISO[] = { }; static const PinMap PinMap_SPI_SSEL[] = { - {PM3, SPI_0, PIN_DATA(3, 1)}, + {PM3, SPI_0, PIN_DATA(3, 2)}, {PL6, SPI_1, PIN_DATA(1, 2)}, {NC, NC, 0} }; -void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) +static const PinMap PinMap_SPISLAVE_SCLK[] = { + {PM0, SPI_0, PIN_DATA(3, 0)}, + {PP0, SPI_1, PIN_DATA(1, 0)}, + {NC, NC, 0} +}; + +void spi_init(spi_t *t_obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) { + struct spi_s *obj = SPI_S(t_obj); // Check pin parameters SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI); SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO); @@ -63,12 +105,18 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel obj->p_obj.p_instance = TSB_TSPI0; TSB_CG_FSYSENA_IPENA18 = ENABLE; TSB_CG_FSYSENA_IPENA11 = ENABLE; +#if DEVICE_SPI_ASYNCH + obj->irqn = (uint32_t)&SPI_CH0_IRQN_TBL; +#endif break; case SPI_1: obj->p_obj.p_instance = TSB_TSPI1; TSB_CG_FSYSENA_IPENA19 = ENABLE; TSB_CG_FSYSENA_IPENA13 = ENABLE; TSB_CG_FSYSENA_IPENA10 = ENABLE; +#if DEVICE_SPI_ASYNCH + obj->irqn = (uint32_t)&SPI_CH1_IRQN_TBL; +#endif break; default: error("Cannot found SPI module corresponding with input pins."); @@ -79,6 +127,7 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel pinmap_pinout(mosi, PinMap_SPI_MOSI); pinmap_pinout(miso, PinMap_SPI_MISO); pinmap_pinout(sclk, PinMap_SPI_SCLK); + obj->Slave_SCK = sclk; if (ssel != NC) { pinmap_pinout(ssel, PinMap_SPI_SSEL); @@ -113,7 +162,7 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel obj->p_obj.init.cnt3.rffllclr = TSPI_RX_BUFF_CLR_DONE; // receive buffer clear //baudrate settings - spi_frequency(obj, (int)INITIAL_SPI_FREQ); + spi_frequency(t_obj, (int)INITIAL_SPI_FREQ); //Format Control 0 settings obj->p_obj.init.fmr0.dir = TSPI_DATA_DIRECTION_MSB; // MSB bit first @@ -141,14 +190,16 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel tspi_init(&obj->p_obj); } -void spi_free(spi_t *obj) +void spi_free(spi_t *t_obj) { + struct spi_s *obj = SPI_S(t_obj); tspi_deinit(&obj->p_obj); obj->module = (SPIName)NC; } -void spi_format(spi_t *obj, int bits, int mode, int slave) +void spi_format(spi_t *t_obj, int bits, int mode, int slave) { + struct spi_s *obj = SPI_S(t_obj); MBED_ASSERT((slave == 0U) || (slave == 1U)); // 0: master mode, 1: slave mode MBED_ASSERT((bits >= 8) && (bits <= 32)); @@ -167,11 +218,16 @@ void spi_format(spi_t *obj, int bits, int mode, int slave) obj->p_obj.init.fmr0.ckpha = TSPI_SERIAL_CK_1ST_EDGE; } + if(slave) { + pinmap_pinout(obj->Slave_SCK, PinMap_SPISLAVE_SCLK); + obj->p_obj.init.cnt1.mstr = TSPI_SLAVE_OPERATION; // Slave mode operation + } tspi_init(&obj->p_obj); } -void spi_frequency(spi_t *obj, int hz) +void spi_frequency(spi_t *t_obj, int hz) { + struct spi_s *obj = SPI_S(t_obj); uint8_t brs = 0; uint8_t brck = 0; uint16_t prsck = 1; @@ -203,8 +259,9 @@ void spi_frequency(spi_t *obj, int hz) tspi_init(&obj->p_obj); } -int spi_master_write(spi_t *obj, int value) +int spi_master_write(spi_t *t_obj, int value) { + struct spi_s *obj = SPI_S(t_obj); uint8_t ret_value = 0; tspi_transmit_t send_obj; @@ -223,14 +280,14 @@ int spi_master_write(spi_t *obj, int value) return ret_value; } -int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, +int spi_master_block_write(spi_t *t_obj, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, char write_fill) { int total = (tx_length > rx_length) ? tx_length : rx_length; for (int i = 0; i < total; i++) { char out = (i < tx_length) ? tx_buffer[i] : write_fill; - char in = spi_master_write(obj, out); + char in = spi_master_write(t_obj, out); if (i < rx_length) { rx_buffer[i] = in; } @@ -239,8 +296,46 @@ int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, return total; } -int spi_busy(spi_t *obj) +int spi_slave_receive(spi_t *t_obj) { + struct spi_s *obj = SPI_S(t_obj); + int ret = 1; + uint32_t status; + + tspi_get_status(&obj->p_obj, &status); + if((status & (TSPI_RX_REACH_FILL_LEVEL_MASK)) == 0) { + ret = 0; + } + + return ret; +} + +int spi_slave_read(spi_t *t_obj) +{ + struct spi_s *obj = SPI_S(t_obj); + uint8_t ret_value = 0; + + ret_value = obj->p_obj.p_instance->DR & 0xFF; + + // Receive Complete Flag is clear. + obj->p_obj.p_instance->SR |= TSPI_RX_DONE_CLR; + obj->p_obj.p_instance->CR1 &= TSPI_TRXE_DISABLE_MASK; + + return ret_value; +} + +void spi_slave_write(spi_t *t_obj, int value) +{ + struct spi_s *obj = SPI_S(t_obj); + + // Enable TSPI Transmission Control. + obj->p_obj.p_instance->CR1 |= TSPI_TRXE_ENABLE; + obj->p_obj.p_instance->DR = value & 0xFF; +} + +int spi_busy(spi_t *t_obj) +{ + struct spi_s *obj = SPI_S(t_obj); int ret = 1; uint32_t status = 0; @@ -253,8 +348,9 @@ int spi_busy(spi_t *obj) return ret; } -uint8_t spi_get_module(spi_t *obj) +uint8_t spi_get_module(spi_t *t_obj) { + struct spi_s *obj = SPI_S(t_obj); return (uint8_t)(obj->module); } @@ -290,10 +386,173 @@ const PinMap *spi_slave_miso_pinmap() const PinMap *spi_slave_clk_pinmap() { - return PinMap_SPI_SCLK; + return PinMap_SPISLAVE_SCLK; } const PinMap *spi_slave_cs_pinmap() { return PinMap_SPI_SSEL; } + +#if DEVICE_SPI_ASYNCH + +void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, + uint32_t handler, uint32_t event, DMAUsage hint) +{ + struct spi_s *spiobj = SPI_S(obj); + spi_irq_t *p_irqn = (spi_irq_t *)spiobj->irqn; + bool use_tx = (tx != NULL && tx_length > 0); + bool use_rx = (rx != NULL && rx_length > 0); + + // don't do anything, if the buffers aren't valid + if (!use_tx && !use_rx) { + return; + } + + disable_irq(spiobj->irqn); + + spiobj->p_obj.p_instance->CR1 &= TSPI_TRXE_DISABLE_MASK; + spiobj->p_obj.p_instance->SR |= (TSPI_TX_DONE_CLR | TSPI_RX_DONE_CLR); + spiobj->p_obj.p_instance->CR3 |= (TSPI_TX_BUFF_CLR_DONE | TSPI_RX_BUFF_CLR_DONE); + + clear_irq(spiobj->irqn); + + obj->tx_buff.buffer = (void *)tx; + obj->tx_buff.length = tx_length; + obj->tx_buff.pos = 0; + obj->rx_buff.buffer = (void *)rx; + obj->rx_buff.length = rx_length; + obj->rx_buff.pos = 0; + spiobj->event = 0; + spiobj->state = SPI_TRANSFER_STATE_IDLE; + + NVIC_SetVector(p_irqn->Error, (uint32_t)handler); + NVIC_SetVector(p_irqn->Tx, (uint32_t)handler); + NVIC_SetVector(p_irqn->Rx, (uint32_t)handler); + + // Enable Error Interrupt, Receive complete interrupt and Transmit complete interrupt + spiobj->p_obj.p_instance->CR2 |= (TSPI_TX_INT_ENABLE | TSPI_RX_INT_ENABLE | TSPI_ERR_INT_ENABLE); + + if (use_tx && use_rx) { + spiobj->max_size = tx_length < rx_length ? rx_length:tx_length; + spiobj->p_obj.p_instance->CR1 |= TSPI_TRXE_ENABLE; + spiobj->p_obj.p_instance->DR = ((uint8_t *)obj->tx_buff.buffer)[obj->tx_buff.pos] & 0xFF; + } else if(use_tx) { + spiobj->max_size = tx_length; + spiobj->p_obj.p_instance->CR1 |= TSPI_TRXE_ENABLE; + spiobj->p_obj.p_instance->DR = ((uint8_t *)obj->tx_buff.buffer)[obj->tx_buff.pos] & 0xFF; + } else if(use_rx) { + spiobj->max_size = rx_length; + spiobj->p_obj.p_instance->CR1 |= TSPI_TRXE_ENABLE; + spiobj->p_obj.p_instance->DR = 0xFF; + } + + spiobj->state = SPI_TRANSFER_STATE_BUSY; + NVIC_EnableIRQ(p_irqn->Error); + NVIC_EnableIRQ(p_irqn->Tx); + NVIC_EnableIRQ(p_irqn->Rx); +} + +uint32_t spi_irq_handler_asynch(spi_t *obj) +{ + struct spi_s *spiobj = SPI_S(obj); + spi_irq_handler(obj); + return ((spiobj->event & SPI_EVENT_ALL)| SPI_EVENT_INTERNAL_TRANSFER_COMPLETE) ; +} + +uint8_t spi_active(spi_t *obj) +{ + struct spi_s *spiobj = SPI_S(obj); + uint8_t ret_val = 0; + + if (spiobj->state != SPI_TRANSFER_STATE_IDLE) { + ret_val = 1; + } + + return ret_val; +} + +void spi_abort_asynch(spi_t *obj) +{ + struct spi_s *spiobj = SPI_S(obj); + + disable_irq(spiobj->irqn); + clear_irq(spiobj->irqn); + tspi_init(&spiobj->p_obj); +} + +static void spi_irq_handler(spi_t *obj) +{ + struct spi_s *spiobj = SPI_S(obj); + + // Check for revceive complete flag. + if((spiobj->p_obj.p_instance->SR & TSPI_RX_DONE) && + (spiobj->p_obj.p_instance->SR & TSPI_RX_REACH_FILL_LEVEL_MASK)) { + // Check receiver FIFO level + uint8_t rlvl = spiobj->p_obj.p_instance->SR & 0xF; + + while((rlvl != 0) && (obj->rx_buff.pos < obj->rx_buff.length)) { + ((uint8_t *)obj->rx_buff.buffer)[obj->rx_buff.pos++] = spiobj->p_obj.p_instance->DR & 0xFF; + rlvl--; + } + + if(obj->rx_buff.pos == spiobj->max_size) { + spiobj->state = SPI_TRANSFER_STATE_IDLE; + } + // Clear rx buffer + spiobj->p_obj.p_instance->CR3 |= TSPI_RX_BUFF_CLR_DONE; + } + + // Check for transmit completion flag + if(spiobj->p_obj.p_instance->SR & TSPI_TX_DONE) { + obj->tx_buff.pos++; + spiobj->p_obj.p_instance->SR |= TSPI_RX_DONE_CLR; + + if(obj->tx_buff.pos == (spiobj->max_size)) { + spiobj->state = SPI_TRANSFER_STATE_IDLE; + } + + if((obj->tx_buff.pos < obj->tx_buff.length) && (obj->tx_buff.pos < spiobj->max_size)) { + spiobj->p_obj.p_instance->DR = (((uint8_t *)obj->tx_buff.buffer)[obj->tx_buff.pos] & 0xFF); + } else if (obj->tx_buff.pos < spiobj->max_size) { + spiobj->p_obj.p_instance->DR = 0xFF; + } + } + + // Check for error flag + if(spiobj->p_obj.p_instance->ERR) { + spiobj->event = SPI_EVENT_ERROR; + spiobj->state = SPI_TRANSFER_STATE_IDLE; + disable_irq(spiobj->irqn); + spiobj->p_obj.p_instance->SR |= (TSPI_TX_DONE_CLR | TSPI_RX_DONE_CLR); + spiobj->p_obj.p_instance->CR3 |= (TSPI_TX_BUFF_CLR_DONE | TSPI_RX_BUFF_CLR_DONE); + clear_irq(spiobj->irqn); + return; + } + + if(spiobj->state == SPI_TRANSFER_STATE_IDLE) { + spiobj->event = SPI_EVENT_COMPLETE; + disable_irq(spiobj->irqn); + spiobj->p_obj.p_instance->SR |= (TSPI_TX_DONE_CLR | TSPI_RX_DONE_CLR); + spiobj->p_obj.p_instance->CR3 |= (TSPI_TX_BUFF_CLR_DONE | TSPI_RX_BUFF_CLR_DONE); + clear_irq(spiobj->irqn); + } +} + +static void disable_irq(uint32_t irqn) +{ + spi_irq_t *p_irqn = (spi_irq_t *)irqn; + NVIC_DisableIRQ(p_irqn->Tx); + NVIC_DisableIRQ(p_irqn->Rx); + NVIC_DisableIRQ(p_irqn->Error); +} + +static void clear_irq(uint32_t irqn) +{ + spi_irq_t *p_irqn = (spi_irq_t *)irqn; + NVIC_ClearPendingIRQ(p_irqn->Tx); + NVIC_ClearPendingIRQ(p_irqn->Rx); + NVIC_ClearPendingIRQ(p_irqn->Error); +} + +#endif diff --git a/targets/targets.json b/targets/targets.json index f624ca73db..070446e309 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -8693,11 +8693,16 @@ "PORTINOUT", "PORTOUT", "PWMOUT", + "RTC", "SERIAL", + "SERIAL_FC", "SLEEP", "SPI", + "SPISLAVE", + "SPI_ASYNCH", "I2C", "I2CSLAVE", + "I2C_ASYNCH", "STDIO_MESSAGES", "MPU" ],