Merge pull request #11101 from kyle-cypress/pr/spi-i2c-fixes

PSoC 6 I2C and SPI driver updates
pull/11099/head
Seppo Takalo 2019-07-26 10:53:07 +03:00 committed by GitHub
commit 7d15882746
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 208 additions and 164 deletions

View File

@ -17,6 +17,8 @@
#include "i2c_api.h"
#include "cyhal_i2c.h"
#include "cyhal_utils.h"
#include "cyhal_hwmgr.h"
#include "mbed_error.h"
#include "mbed_assert.h"
#include "mbed_critical.h"
@ -84,12 +86,24 @@ static void cy_i2c_event_handler(void *handler_arg, cyhal_i2c_irq_event_t event)
void i2c_init(i2c_t *obj, PinName sda, PinName scl)
{
struct i2c_s *i2c = cy_get_i2c(obj);
if (CY_RSLT_SUCCESS != cyhal_i2c_init(&(i2c->hal_i2c), sda, scl, NULL)) {
cy_rslt_t result = cyhal_i2c_init(&(i2c->hal_i2c), sda, scl, NULL);
if (result == CYHAL_HWMGR_RSLT_ERR_INUSE) {
// MBED I2C driver currently does not support free, so we will allow I2C to be reallocated.
// TODO: once the the I2C driver properly supports free, this need to be fixed so that clocks and pins are no longer leaked.
cyhal_hwmgr_free(&(i2c->hal_i2c.resource));
cyhal_hwmgr_set_unconfigured(i2c->hal_i2c.resource.type, i2c->hal_i2c.resource.block_num, i2c->hal_i2c.resource.channel_num);
cyhal_resource_inst_t pin_rsc = cyhal_utils_get_gpio_resource(sda);
cyhal_hwmgr_free(&pin_rsc);
pin_rsc = cyhal_utils_get_gpio_resource(scl);
cyhal_hwmgr_free(&pin_rsc);
result = cyhal_i2c_init(&(i2c->hal_i2c), sda, scl, NULL);
}
if (CY_RSLT_SUCCESS != result) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_I2C, MBED_ERROR_CODE_FAILED_OPERATION), "cyhal_i2c_init");
}
i2c->cfg.is_slave = false;
i2c->cfg.address = 0;
i2c->cfg.frequencyhal_hz = 400;
i2c->cfg.frequencyhal_hz = 400000;
i2c->async_handler = NULL;
cyhal_i2c_register_irq(&(i2c->hal_i2c), &cy_i2c_event_handler, obj);
cyhal_i2c_irq_enable(&(i2c->hal_i2c), (cyhal_i2c_irq_event_t)(CYHAL_I2C_SLAVE_READ_EVENT | CYHAL_I2C_SLAVE_WRITE_EVENT | CYHAL_I2C_SLAVE_ERR_EVENT | CYHAL_I2C_SLAVE_RD_CMPLT_EVENT | CYHAL_I2C_SLAVE_WR_CMPLT_EVENT | CYHAL_I2C_MASTER_ERR_EVENT | CYHAL_I2C_MASTER_RD_CMPLT_EVENT | CYHAL_I2C_MASTER_WR_CMPLT_EVENT), true);
@ -112,14 +126,17 @@ int i2c_start(i2c_t *obj)
int i2c_stop(i2c_t *obj)
{
// Not supported; start/stop is generated by i2c_read/i2c_write
return -1;
struct i2c_s *i2c = cy_get_i2c(obj);
if (i2c->hal_i2c.context.state != CY_SCB_I2C_IDLE) {
return Cy_SCB_I2C_MasterSendStop(i2c->hal_i2c.base, CY_I2C_DEFAULT_TIMEOUT, &(i2c->hal_i2c.context));
}
return 0;
}
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
{
struct i2c_s *i2c = cy_get_i2c(obj);
if (CY_RSLT_SUCCESS != cyhal_i2c_master_recv(&(i2c->hal_i2c), address >> 1, (uint8_t *)data, (uint16_t)length, CY_I2C_DEFAULT_TIMEOUT)) {
if (CY_RSLT_SUCCESS != cyhal_i2c_master_read(&(i2c->hal_i2c), address >> 1, (uint8_t *)data, (uint16_t)length, CY_I2C_DEFAULT_TIMEOUT)) {
return (int)I2C_ERROR_NO_SLAVE;
}
return length;
@ -128,7 +145,7 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
{
struct i2c_s *i2c = cy_get_i2c(obj);
if (CY_RSLT_SUCCESS != cyhal_i2c_master_send(&(i2c->hal_i2c), address >> 1, (const uint8_t *)data, (uint16_t)length, CY_I2C_DEFAULT_TIMEOUT)) {
if (CY_RSLT_SUCCESS != cyhal_i2c_master_write(&(i2c->hal_i2c), address >> 1, (const uint8_t *)data, (uint16_t)length, CY_I2C_DEFAULT_TIMEOUT)) {
return (int)I2C_ERROR_NO_SLAVE;
}
// NOTE: HAL does not report how many bytes were actually sent in case of early NAK
@ -153,7 +170,10 @@ int i2c_byte_read(i2c_t *obj, int last)
int i2c_byte_write(i2c_t *obj, int data)
{
struct i2c_s *i2c = cy_get_i2c(obj);
cy_en_scb_i2c_status_t status = Cy_SCB_I2C_MasterWriteByte(i2c->hal_i2c.base, (uint8_t)data, CY_I2C_DEFAULT_TIMEOUT, &(i2c->hal_i2c.context));
// If we have not yet written the address, the first byte being sent is the address.
cy_en_scb_i2c_status_t status = i2c->hal_i2c.context.state == CY_SCB_I2C_IDLE
? Cy_SCB_I2C_MasterSendStart(i2c->hal_i2c.base, data >> 1, CY_SCB_I2C_WRITE_XFER, CY_I2C_DEFAULT_TIMEOUT, &(i2c->hal_i2c.context))
: Cy_SCB_I2C_MasterWriteByte(i2c->hal_i2c.base, (uint8_t)data, CY_I2C_DEFAULT_TIMEOUT, &(i2c->hal_i2c.context));
switch (status) {
case CY_SCB_I2C_MASTER_MANUAL_TIMEOUT:
return 2;
@ -203,7 +223,7 @@ int i2c_slave_receive(i2c_t *obj)
int i2c_slave_read(i2c_t *obj, char *data, int length)
{
struct i2c_s *i2c = cy_get_i2c(obj);
if (CY_RSLT_SUCCESS != cyhal_i2c_slave_recv(&(i2c->hal_i2c), (uint8_t *)data, (uint16_t)length, CY_I2C_DEFAULT_TIMEOUT)) {
if (CY_RSLT_SUCCESS != cyhal_i2c_slave_config_read_buff(&(i2c->hal_i2c), (uint8_t *)data, (uint16_t)length)) {
return 0;
}
return 1;
@ -212,7 +232,7 @@ int i2c_slave_read(i2c_t *obj, char *data, int length)
int i2c_slave_write(i2c_t *obj, const char *data, int length)
{
struct i2c_s *i2c = cy_get_i2c(obj);
if (CY_RSLT_SUCCESS != cyhal_i2c_slave_send(&(i2c->hal_i2c), (const uint8_t *)data, (uint16_t)length, CY_I2C_DEFAULT_TIMEOUT)) {
if (CY_RSLT_SUCCESS != cyhal_i2c_slave_config_write_buff(&(i2c->hal_i2c), (const uint8_t *)data, (uint16_t)length)) {
return 0;
}
return 1;
@ -239,8 +259,8 @@ void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx,
i2c->async_rx_size = rx_length;
i2c->async_handler = (void (*)(void))handler;
core_util_critical_section_exit();
if (CY_RSLT_SUCCESS != cyhal_i2c_transfer_async(&(i2c->hal_i2c), tx, tx_length, rx, rx_length, address)) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_I2C, MBED_ERROR_CODE_FAILED_OPERATION), "cyhal_i2c_transfer_async");
if (CY_RSLT_SUCCESS != cyhal_i2c_master_transfer_async(&(i2c->hal_i2c), address, tx, tx_length, rx, rx_length)) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_I2C, MBED_ERROR_CODE_FAILED_OPERATION), "cyhal_i2c_master_transfer_async");
}
}

View File

@ -112,7 +112,9 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
if (CY_RSLT_SUCCESS != cyhal_spi_init(&(spi->hal_spi), mosi, miso, sclk, ssel, NULL, (uint8_t)bits, hal_mode, slave != 0)) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SPI, MBED_ERROR_CODE_FAILED_OPERATION), "cyhal_spi_init");
}
spi_frequency(obj, hz);
if (spi->hz != 0) {
spi_frequency(obj, hz);
}
}
void spi_frequency(spi_t *obj, int hz)
@ -127,11 +129,14 @@ void spi_frequency(spi_t *obj, int hz)
int spi_master_write(spi_t *obj, int value)
{
struct spi_s *spi = cy_get_spi(obj);
uint8_t received;
if (CY_RSLT_SUCCESS != cyhal_spi_transfer(&(spi->hal_spi), (const uint8_t *)value, 1, &received, 1, 0)) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SPI, MBED_ERROR_CODE_FAILED_OPERATION), "cyhal_spi_transfer");
uint32_t received;
if (CY_RSLT_SUCCESS != cyhal_spi_write(&(spi->hal_spi), (uint32_t)value)) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SPI, MBED_ERROR_CODE_FAILED_OPERATION), "cyhal_spi_write");
}
return received;
if (CY_RSLT_SUCCESS != cyhal_spi_read(&(spi->hal_spi), &received)) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SPI, MBED_ERROR_CODE_FAILED_OPERATION), "cyhal_spi_read");
}
return (int)received;
}
int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, char write_fill)

View File

@ -350,7 +350,7 @@ typedef struct {
uint16_t pending;
void *rx_buffer;
uint32_t rx_buffer_size;
void *tx_buffer;
const void *tx_buffer;
uint32_t tx_buffer_size;
bool is_async;
#else

View File

@ -68,6 +68,17 @@ extern "C" {
* \{
*/
/** Calculate the peri clock divider value that need to be set to reach frequency closest to the input frequency
*
* @param[in] frequency The desired frequency
* @param[in] frac_bits The number of fractional bits that the divider has
* @return The calculate divider value to set, NOTE a divider value of x divide the frequency by (x+1)
*/
static inline uint32_t cyhal_divider_value(uint32_t frequency, uint32_t frac_bits)
{
return ((cy_PeriClkFreqHz * (1 << frac_bits)) + (frequency / 2)) / frequency - 1;
}
/** Converts the provided gpio pin to a resource instance object
*
* @param[in] pin The pin to get a resource object for

View File

@ -33,8 +33,20 @@
#define PENDING_TX 2
#define PENDING_TX_RX 3
#define SCB_PERI_CLOCK_SLAVE 15000000
#define SCB_PERI_CLOCK_MASTER 1800000
/* Must be between 1.55 MHz and 12.8 MHz for running i2c master at 100KHz */
#define SCB_PERI_CLOCK_SLAVE_STD 8000000
/* Must be between 7.82 MHz and 15.38 MHz for running i2c master at 400KHz */
#define SCB_PERI_CLOCK_SLAVE_FST 12500000
/* Must be between 15.84 MHz and 89.0 MHz for running i2c master at 1MHz */
#define SCB_PERI_CLOCK_SLAVE_FSTP 50000000
/* Must be between 1.55 MHz and 3.2 MHz for running i2c slave at 100KHz */
#define SCB_PERI_CLOCK_MASTER_STD 2000000
/* Must be between 7.82 MHz and 10 MHz for running i2c slave at 400KHz */
#define SCB_PERI_CLOCK_MASTER_FST 8500000
/* Must be between 14.32 MHz and 25.8 MHz for running i2c slave at 1MHz */
#define SCB_PERI_CLOCK_MASTER_FSTP 20000000
#define CYHAL_I2C_MASTER_DEFAULT_FREQ 100000
static const cy_stc_scb_i2c_config_t default_i2c_config = {
.i2cMode = CY_SCB_I2C_MASTER,
@ -429,10 +441,45 @@ static void (*cyhal_i2c_interrupts_dispatcher_table[CY_IP_MXSCB_INSTANCES])(void
#endif
};
static uint32_t cyhal_divider_value(uint32_t frequency, uint32_t frac_bits)
static uint32_t cyhal_set_peri_divider(cyhal_i2c_t *obj, uint32_t freq, bool is_slave)
{
/* I2C use peripheral clock */
return ((cy_PeriClkFreqHz * (1 << frac_bits)) + (frequency / 2)) / frequency;
/* Return the actual data rate on success, 0 otherwise */
uint32_t peri_freq = 0;
if (freq == 0)
{
return 0;
}
if (freq <= CY_SCB_I2C_STD_DATA_RATE)
{
peri_freq = is_slave ? SCB_PERI_CLOCK_SLAVE_STD : SCB_PERI_CLOCK_MASTER_STD;
}
else if (freq <= CY_SCB_I2C_FST_DATA_RATE)
{
peri_freq = is_slave ? SCB_PERI_CLOCK_SLAVE_FST : SCB_PERI_CLOCK_MASTER_FST;
}
else if (freq <= CY_SCB_I2C_FSTP_DATA_RATE)
{
peri_freq = is_slave ? SCB_PERI_CLOCK_SLAVE_FSTP : SCB_PERI_CLOCK_MASTER_FSTP;
}
else
{
return 0;
}
Cy_SysClk_PeriphAssignDivider((en_clk_dst_t)get_scb_cls(obj->resource.block_num), obj->clock.div_type, obj->clock.div_num);
Cy_SysClk_PeriphDisableDivider(obj->clock.div_type, obj->clock.div_num);
Cy_SysClk_PeriphSetDivider(obj->clock.div_type, obj->clock.div_num, cyhal_divider_value(peri_freq, 0u));
Cy_SysClk_PeriphEnableDivider(obj->clock.div_type, obj->clock.div_num);
/* According to PDL API Reference Guide - Cy_SysClk_PeriphGetFrequency() use only for i2c master role */
if(!is_slave)
{
return Cy_SCB_I2C_SetDataRate(obj->base, freq, Cy_SysClk_PeriphGetFrequency(obj->clock.div_type, obj->clock.div_num));
}
else
{
return Cy_SCB_I2C_GetDataRate(obj->base, Cy_SysClk_PeriphGetFrequency(obj->clock.div_type, obj->clock.div_num));
}
}
/* Start API implementing */
@ -454,13 +501,12 @@ cy_rslt_t cyhal_i2c_init(cyhal_i2c_t *obj, cyhal_gpio_t sda, cyhal_gpio_t scl, c
{
return CYHAL_I2C_RSLT_ERR_INVALID_PIN;
}
const cyhal_resource_inst_t *rsc = scl_map->inst;
cy_rslt_t result = cyhal_hwmgr_reserve(rsc);
obj->resource = *(scl_map->inst);
cy_rslt_t result = cyhal_hwmgr_reserve(&(obj->resource));
if (result != CY_RSLT_SUCCESS)
{
return result;
}
obj->resource = *rsc;
/* Reserve the SDA pin */
cyhal_resource_inst_t pin_rsc = cyhal_utils_get_gpio_resource(sda);
@ -468,7 +514,7 @@ cy_rslt_t cyhal_i2c_init(cyhal_i2c_t *obj, cyhal_gpio_t sda, cyhal_gpio_t scl, c
if (result == CY_RSLT_SUCCESS)
{
obj->pin_sda = sda;
}
}
Cy_GPIO_SetHSIOM(CYHAL_GET_PORTADDR(sda), CYHAL_GET_PIN(sda), CY_GPIO_CFG_GET_HSIOM(scl_map->cfg));
Cy_GPIO_SetDrivemode(CYHAL_GET_PORTADDR(sda), CYHAL_GET_PIN(sda), CY_GPIO_DM_OD_DRIVESLOW);
@ -481,10 +527,10 @@ cy_rslt_t cyhal_i2c_init(cyhal_i2c_t *obj, cyhal_gpio_t sda, cyhal_gpio_t scl, c
if (result == CY_RSLT_SUCCESS)
{
obj->pin_scl = scl;
}
}
Cy_GPIO_SetHSIOM(CYHAL_GET_PORTADDR(scl), CYHAL_GET_PIN(scl), CY_GPIO_CFG_GET_HSIOM(scl_map->cfg));
Cy_GPIO_SetDrivemode(CYHAL_GET_PORTADDR(scl), CYHAL_GET_PIN(scl), CY_GPIO_DM_OD_DRIVESLOW);
}
obj->base = CY_SCB_BASE_ADDRESSES[obj->resource.block_num];
@ -504,18 +550,12 @@ cy_rslt_t cyhal_i2c_init(cyhal_i2c_t *obj, cyhal_gpio_t sda, cyhal_gpio_t scl, c
if (result == CY_RSLT_SUCCESS)
{
/* Connect assigned divider to be a clock source for I2C */
Cy_SysClk_PeriphAssignDivider((en_clk_dst_t)get_scb_cls(obj->resource.block_num), obj->clock.div_type, obj->clock.div_num);
/* I2C slave desired data rate is 400 kbps.
* To support this data rate the clk_scb frequency must be in range 7.82 15.38 MHz.
* Find clk_scb valid ranges in TRM section I2C sub-section Oversampling and Bit Rate.
* For clk_peri = 50 MHz, select divider value 4 and get clk_scb = (50 MHz / 4) = 12.5 MHz.
* This clock frequency meets requirements above.
*/
Cy_SysClk_PeriphDisableDivider(obj->clock.div_type, obj->clock.div_num);
Cy_SysClk_PeriphSetDivider(obj->clock.div_type, obj->clock.div_num, cyhal_divider_value(SCB_PERI_CLOCK_SLAVE, 0u));
Cy_SysClk_PeriphEnableDivider(obj->clock.div_type, obj->clock.div_num);
uint32_t dataRate = cyhal_set_peri_divider(obj, CYHAL_I2C_MASTER_DEFAULT_FREQ, false);
if (dataRate == 0)
{
/* Can not reach desired data rate */
result = CYHAL_I2C_RSLT_ERR_CAN_NOT_REACH_DR;
}
}
bool configured = cyhal_hwmgr_is_configured(obj->resource.type, obj->resource.block_num, obj->resource.channel_num);
@ -528,6 +568,7 @@ cy_rslt_t cyhal_i2c_init(cyhal_i2c_t *obj, cyhal_gpio_t sda, cyhal_gpio_t scl, c
(void) Cy_SCB_I2C_Enable(obj->base);
Cy_SysInt_Init(&irqCfg, cyhal_i2c_interrupts_dispatcher_table[obj->resource.block_num]);
NVIC_EnableIRQ(CY_SCB_IRQ_N[obj->resource.block_num]);
obj->irq_cause = CYHAL_I2C_IRQ_NONE;
cyhal_i2c_config_structs[obj->resource.block_num] = obj;
cyhal_i2c_config_structs[obj->resource.block_num]->irq_cause = CYHAL_I2C_IRQ_NONE;
result = cyhal_hwmgr_set_configured(obj->resource.type, obj->resource.block_num, obj->resource.channel_num);
@ -542,9 +583,12 @@ cy_rslt_t cyhal_i2c_init(cyhal_i2c_t *obj, cyhal_gpio_t sda, cyhal_gpio_t scl, c
void cyhal_i2c_free(cyhal_i2c_t *obj)
{
CY_ASSERT(NULL != obj);
if (CYHAL_RSC_INVALID != obj->resource.type)
{
IRQn_Type irqn = CY_SCB_IRQ_N[obj->resource.block_num];
NVIC_DisableIRQ(irqn);
cyhal_hwmgr_set_unconfigured(obj->resource.type, obj->resource.block_num, obj->resource.channel_num);
cyhal_hwmgr_free(&(obj->resource));
obj->base = NULL;
@ -570,9 +614,8 @@ void cyhal_i2c_free(cyhal_i2c_t *obj)
cy_rslt_t cyhal_i2c_set_config(cyhal_i2c_t *obj, const cyhal_i2c_cfg_t *cfg)
{
(void) Cy_SCB_I2C_Disable(obj->base, &obj->context);
uint32_t dataRate;
cy_stc_scb_i2c_config_t config_structure = default_i2c_config;
cy_stc_scb_i2c_config_t config_structure = default_i2c_config;
config_structure.i2cMode = (cfg->is_slave)
? CY_SCB_I2C_SLAVE
: CY_SCB_I2C_MASTER;
@ -586,28 +629,13 @@ cy_rslt_t cyhal_i2c_set_config(cyhal_i2c_t *obj, const cyhal_i2c_cfg_t *cfg)
}
/* Set data rate */
if (!cfg->is_slave)
uint32_t dataRate = cyhal_set_peri_divider(obj, cfg->frequencyhal_hz, cfg->is_slave);
if (dataRate == 0)
{
Cy_SysClk_PeriphAssignDivider((en_clk_dst_t)get_scb_cls(obj->resource.block_num), obj->clock.div_type, obj->clock.div_num);
/* I2C master desired data rate is 100 kbps.
* To support this data rate the clk_scb frequency must be in range 1.55 - 3.2 MHz.
* Find clk_scb valid ranges in TRM section I2C sub-section Oversampling and Bit Rate.
* For clk_peri = 50 MHz, select divider value 32 and get clk_scb = (50 MHz / 32) = 1.563 MHz.
* This clock frequency meets requirements above.
*/
Cy_SysClk_PeriphDisableDivider(obj->clock.div_type, obj->clock.div_num);
Cy_SysClk_PeriphSetDivider (obj->clock.div_type, obj->clock.div_num, cyhal_divider_value(SCB_PERI_CLOCK_MASTER, 0u));
Cy_SysClk_PeriphEnableDivider(obj->clock.div_type, obj->clock.div_num);
dataRate = Cy_SCB_I2C_SetDataRate(obj->base, (uint32_t)cfg->frequencyhal_hz, Cy_SysClk_PeriphGetFrequency(obj->clock.div_type, obj->clock.div_num));
if ((dataRate > cfg->frequencyhal_hz) || (dataRate == 0U))
{
/* Can not reach desired data rate */
return CYHAL_I2C_RSLT_ERR_CAN_NOT_REACH_DR;
}
/* Can not reach desired data rate */
return CYHAL_I2C_RSLT_ERR_CAN_NOT_REACH_DR;
}
cy_rslt_t result = (cy_rslt_t)Cy_SCB_I2C_Init(obj->base, &config_structure, &(obj->context));
(void) Cy_SCB_I2C_Enable(obj->base);
@ -615,7 +643,7 @@ cy_rslt_t cyhal_i2c_set_config(cyhal_i2c_t *obj, const cyhal_i2c_cfg_t *cfg)
return result;
}
cy_rslt_t cyhal_i2c_master_send(cyhal_i2c_t *obj, uint16_t dev_addr, const uint8_t *data, uint16_t size, uint32_t timeout)
cy_rslt_t cyhal_i2c_master_write(cyhal_i2c_t *obj, uint16_t dev_addr, const uint8_t *data, uint16_t size, uint32_t timeout)
{
cy_en_scb_i2c_status_t status = CY_SCB_I2C_SUCCESS;
@ -649,7 +677,7 @@ cy_rslt_t cyhal_i2c_master_send(cyhal_i2c_t *obj, uint16_t dev_addr, const uint8
return status;
}
cy_rslt_t cyhal_i2c_master_recv(cyhal_i2c_t *obj, uint16_t dev_addr, uint8_t *data, uint16_t size, uint32_t timeout)
cy_rslt_t cyhal_i2c_master_read(cyhal_i2c_t *obj, uint16_t dev_addr, uint8_t *data, uint16_t size, uint32_t timeout)
{
cy_en_scb_i2c_status_t status = CY_SCB_I2C_SUCCESS;
cy_en_scb_i2c_command_t ack = CY_SCB_I2C_ACK;
@ -687,25 +715,25 @@ cy_rslt_t cyhal_i2c_master_recv(cyhal_i2c_t *obj, uint16_t dev_addr, uint8_t *da
return status;
}
cy_rslt_t cyhal_i2c_slave_send(cyhal_i2c_t *obj, const uint8_t *data, uint16_t size, uint32_t timeout)
cy_rslt_t cyhal_i2c_slave_config_write_buff(cyhal_i2c_t *obj, const uint8_t *data, uint16_t size)
{
if (obj->context.state == CY_SCB_I2C_IDLE)
if (obj->context.state == CY_SCB_I2C_IDLE)
{
Cy_SCB_I2C_SlaveConfigReadBuf(obj->base, (uint8_t *)data, size, &obj->context);
}
}
return CY_RSLT_SUCCESS;
}
cy_rslt_t cyhal_i2c_slave_recv(cyhal_i2c_t *obj, uint8_t *data, uint16_t size, uint32_t timeout)
cy_rslt_t cyhal_i2c_slave_config_read_buff(cyhal_i2c_t *obj, uint8_t *data, uint16_t size)
{
if (obj->context.state == CY_SCB_I2C_IDLE)
{
{
Cy_SCB_I2C_SlaveConfigWriteBuf(obj->base, (uint8_t *)data, size, &obj->context);
}
return CY_RSLT_SUCCESS;
}
cy_rslt_t cyhal_i2c_mem_write(cyhal_i2c_t *obj, uint16_t address, uint16_t mem_addr, uint16_t mem_addr_size, const uint8_t *data, uint16_t size, uint32_t timeout)
cy_rslt_t cyhal_i2c_master_mem_write(cyhal_i2c_t *obj, uint16_t address, uint16_t mem_addr, uint16_t mem_addr_size, const uint8_t *data, uint16_t size, uint32_t timeout)
{
cy_en_scb_i2c_status_t status = CY_SCB_I2C_SUCCESS;
@ -753,7 +781,7 @@ cy_rslt_t cyhal_i2c_mem_write(cyhal_i2c_t *obj, uint16_t address, uint16_t mem_a
return status;
}
cy_rslt_t cyhal_i2c_mem_read(cyhal_i2c_t *obj, uint16_t address, uint16_t mem_addr, uint16_t mem_addr_size, uint8_t *data, uint16_t size, uint32_t timeout)
cy_rslt_t cyhal_i2c_master_mem_read(cyhal_i2c_t *obj, uint16_t address, uint16_t mem_addr, uint16_t mem_addr_size, uint8_t *data, uint16_t size, uint32_t timeout)
{
cy_en_scb_i2c_status_t status = CY_SCB_I2C_SUCCESS;
cy_en_scb_i2c_command_t ack = CY_SCB_I2C_ACK;
@ -779,7 +807,7 @@ cy_rslt_t cyhal_i2c_mem_read(cyhal_i2c_t *obj, uint16_t address, uint16_t mem_ad
{
status = Cy_SCB_I2C_MasterWriteByte(obj->base, (uint8_t)(mem_addr & 0x00FF), timeout, &obj->context);
}
if (status == CY_SCB_I2C_SUCCESS)
{
status = Cy_SCB_I2C_MasterSendReStart(obj->base, address, CY_SCB_I2C_READ_XFER, timeout, &obj->context);
@ -814,7 +842,7 @@ cy_rslt_t cyhal_i2c_mem_read(cyhal_i2c_t *obj, uint16_t address, uint16_t mem_ad
return status;
}
cy_rslt_t cyhal_i2c_transfer_async(cyhal_i2c_t *obj, const void *tx, size_t tx_size, void *rx, size_t rx_size, uint16_t address)
cy_rslt_t cyhal_i2c_master_transfer_async(cyhal_i2c_t *obj, uint16_t address, const void *tx, size_t tx_size, void *rx, size_t rx_size)
{
obj->rx_config.slaveAddress = address;
obj->tx_config.slaveAddress = address;
@ -906,7 +934,7 @@ static cyhal_i2c_irq_event_t cyhal_convert_interrupt_cause(uint32_t pdl_cause)
break;
case CY_SCB_I2C_MASTER_ERR_EVENT:
cause = CYHAL_I2C_MASTER_ERR_EVENT;
break;
break;
default:
cause = CYHAL_I2C_IRQ_NONE;
break;

View File

@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include "cyhal_implementation.h"
#include "cyhal_hwmgr.h"
#ifdef CY_IP_MXSCB
@ -300,7 +301,6 @@ static void (*cyhal_spi_cb_wrapper_table[CY_IP_MXSCB_INSTANCES])(uint32_t event)
static void cyhal_spi_interrupts_dispatcher_IRQHandler(uint32_t spi_num)
{
cyhal_spi_t *obj = cyhal_spi_config_structs[spi_num];
void *buf;
if (NULL == obj)
{
@ -320,15 +320,15 @@ static void cyhal_spi_interrupts_dispatcher_IRQHandler(uint32_t spi_num)
{
/* Start TX Transfer */
obj->pending = PENDING_TX;
buf = obj->tx_buffer;
const uint8_t *buf = obj->tx_buffer;
obj->tx_buffer = NULL;
Cy_SCB_SPI_Transfer(obj->base, buf, NULL, obj->tx_buffer_size, &obj->context);
Cy_SCB_SPI_Transfer(obj->base, (uint8_t *)buf, NULL, obj->tx_buffer_size, &obj->context);
} else if (obj->rx_buffer)
{
/* Start RX Transfer */
obj->pending = PENDING_RX;
buf = obj->rx_buffer;
uint8_t *buf = obj->rx_buffer;
obj->rx_buffer = NULL;
Cy_SCB_SPI_Transfer(obj->base, NULL, buf, obj->rx_buffer_size, &obj->context);
@ -497,6 +497,7 @@ static void cyhal_spi_install_irq(cyhal_spi_t *obj)
Cy_SysInt_Init(&irqCfg, cyhal_spi_interrupts_dispatcher_table[idx]);
NVIC_EnableIRQ(CY_SCB_IRQ_N[idx]);
cyhal_spi_config_structs[idx] = obj;
cyhal_spi_config_structs[idx]->irq_cause = CYHAL_SPI_IRQ_NONE;
}
static cy_en_scb_spi_sclk_mode_t cyhal_convert_mode_sclk(cyhal_spi_mode_t mode)
@ -542,7 +543,7 @@ cy_rslt_t cyhal_spi_init(cyhal_spi_t *obj, cyhal_gpio_t mosi, cyhal_gpio_t miso,
uint8_t bits, cyhal_spi_mode_t mode, bool is_slave)
{
CY_ASSERT(NULL != obj);
cy_rslt_t result = CY_RSLT_SUCCESS;
cyhal_resource_inst_t pin_rsc;
uint8_t ovr_sample_val = SPI_OVERSAMPLE_MIN;
@ -556,12 +557,12 @@ cy_rslt_t cyhal_spi_init(cyhal_spi_t *obj, cyhal_gpio_t mosi, cyhal_gpio_t miso,
if ((NC == sclk) || ((NC == mosi) && (NC == miso)))
return CYHAL_SPI_RSLT_PIN_CONFIG_NOT_SUPPORTED;
const cyhal_resource_pin_mapping_t *mosi_map = NULL;
const cyhal_resource_pin_mapping_t *miso_map = NULL;
const cyhal_resource_pin_mapping_t *sclk_map = NULL;
const cyhal_resource_pin_mapping_t *ssel_map = NULL;
// Reserve the SPI
if (is_slave)
{
@ -595,7 +596,7 @@ cy_rslt_t cyhal_spi_init(cyhal_spi_t *obj, cyhal_gpio_t mosi, cyhal_gpio_t miso,
}
sclk_map = CY_UTILS_GET_RESOURCE(sclk, cyhal_pin_map_scb_spi_m_clk);
}
if ( ((NC != mosi) && (NULL == mosi_map))
|| ((NC != miso) && (NULL == miso_map))
|| (NULL == sclk_map)
@ -652,7 +653,7 @@ cy_rslt_t cyhal_spi_init(cyhal_spi_t *obj, cyhal_gpio_t mosi, cyhal_gpio_t miso,
//reseve the SSEL pin
if ((result == CY_RSLT_SUCCESS) && (NC != ssel))
{
if (is_slave)
if (is_slave)
{
pin_rsc = cyhal_utils_get_gpio_resource(ssel);
result = cyhal_hwmgr_reserve(&pin_rsc);
@ -718,7 +719,7 @@ cy_rslt_t cyhal_spi_init(cyhal_spi_t *obj, cyhal_gpio_t mosi, cyhal_gpio_t miso,
{
result = cyhal_connect_pin(ssel_map);
}
else
else
{
result = cyhal_gpio_init(ssel, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, true);
}
@ -767,6 +768,9 @@ void cyhal_spi_free(cyhal_spi_t *obj)
if (obj->resource.type != CYHAL_RSC_INVALID)
{
IRQn_Type irqn = CY_SCB_IRQ_N[obj->resource.block_num];
NVIC_DisableIRQ(irqn);
cyhal_hwmgr_set_unconfigured(obj->resource.type, obj->resource.block_num, obj->resource.channel_num);
cyhal_hwmgr_free(&(obj->resource));
obj->resource.type = CYHAL_RSC_INVALID;
@ -805,12 +809,6 @@ void cyhal_spi_free(cyhal_spi_t *obj)
}
}
static uint32_t cyhal_divider_value(uint32_t frequency)
{
/* SPI use peripheral clock */
return cy_PeriClkFreqHz / frequency;
}
static inline uint32_t min(uint32_t lhs, uint32_t rhs)
{
return lhs > rhs ? rhs : lhs;
@ -827,7 +825,7 @@ static cy_rslt_t cyhal_int_spi_frequency(cyhal_spi_t *obj, uint32_t hz, uint8_t
{
return CYHAL_SPI_RSLT_BAD_ARGUMENT;
}
cy_rslt_t result = CY_RSLT_SUCCESS;
uint8_t oversample_value;
uint32_t divider_value;
@ -854,8 +852,8 @@ static cy_rslt_t cyhal_int_spi_frequency(cyhal_spi_t *obj, uint32_t hz, uint8_t
continue;
}
divider_value = cyhal_divider_value(hz * oversample_value);
divided_freq = cy_PeriClkFreqHz /divider_value;
divider_value = cyhal_divider_value(hz * oversample_value, 0);
divided_freq = cy_PeriClkFreqHz /(divider_value + 1);
diff = max(oversampled_freq, divided_freq) - min(oversampled_freq, divided_freq);
if (diff < last_diff)
@ -874,16 +872,16 @@ static cy_rslt_t cyhal_int_spi_frequency(cyhal_spi_t *obj, uint32_t hz, uint8_t
else
{
/* Slave requires such frequency: fclk_scb = N / ((0.5 * tclk_scb) 20 nsec - tDSI,
* N is 3 when "Enable Input Glitch Filter" is false and 4 when true.
* N is 3 when "Enable Input Glitch Filter" is false and 4 when true.
* tDSI Is external master delay which is assumed to be 16.66 nsec */
float desired_period_us = 1 / (float)hz * 1e6;
uint32_t required_frequency = (uint32_t)(3e6 / (0.5f * desired_period_us - 36.66f / 1e3));
if (required_frequency > cy_PeriClkFreqHz)
{
return CYHAL_SPI_RSLT_CLOCK_ERROR;
}
/* Use maximum available clock for slave to make it able to work with any master environment */
last_dvdr_val = 1;
}
@ -915,7 +913,7 @@ static void cyhal_set_ssel(cyhal_spi_t *obj)
static void cyhal_reset_ssel(cyhal_spi_t *obj)
{
if ((!obj->is_slave) && (CYHAL_NC_PIN_VALUE != obj->pin_ssel))
if ((!obj->is_slave) && (CYHAL_NC_PIN_VALUE != obj->pin_ssel))
{
cyhal_gpio_write(obj->pin_ssel, SSEL_INACTIVE);
}
@ -974,7 +972,7 @@ cy_rslt_t cyhal_spi_read(cyhal_spi_t *obj, uint32_t *value)
{
return CYHAL_SPI_RSLT_INVALID_PIN_API_NOT_SUPPORTED;
}
while (read_value == CY_SCB_SPI_RX_NO_DATA)
{
read_value = Cy_SCB_SPI_Read(obj->base);
@ -1003,7 +1001,7 @@ cy_rslt_t cyhal_spi_write(cyhal_spi_t *obj, uint32_t value)
{
return CYHAL_SPI_RSLT_INVALID_PIN_API_NOT_SUPPORTED;
}
if (!obj->is_slave)
{
rx_count = Cy_SCB_SPI_GetNumInRxFifo(obj->base);
@ -1019,11 +1017,11 @@ cy_rslt_t cyhal_spi_write(cyhal_spi_t *obj, uint32_t value)
count = Cy_SCB_SPI_Write(obj->base, value);
}
if (!obj->is_slave)
if (!obj->is_slave)
{
while (Cy_SCB_SPI_IsTxComplete(obj->base) == false)
;
while (( Cy_SCB_SPI_GetNumInRxFifo(obj->base) == rx_count ) && (rx_count != Cy_SCB_GetFifoSize(obj->base)))
while (( Cy_SCB_SPI_GetNumInRxFifo(obj->base) == rx_count ) && (rx_count != Cy_SCB_GetFifoSize(obj->base)))
{ /* Wait for RX FIFO not empty */ }
cyhal_reset_ssel(obj);
}
@ -1037,7 +1035,6 @@ cy_rslt_t cyhal_spi_transfer(cyhal_spi_t *obj, const uint8_t *tx, size_t tx_leng
{
uint32_t remaining_rx, remaining_tx, xfr_length;
uint8_t dummy[MAX_DUMMY_SIZE];
uint8_t *bufptr;
if (NULL == obj)
{
@ -1059,71 +1056,67 @@ cy_rslt_t cyhal_spi_transfer(cyhal_spi_t *obj, const uint8_t *tx, size_t tx_leng
xfr_length = (uint32_t) rx_length;
remaining_rx = 0;
remaining_tx = (uint32_t) (tx_length - rx_length);
Cy_SCB_SPI_Transfer(obj->base, (uint8_t *) tx, rx, xfr_length, &(obj->context));
if (xfr_length != 0)
{
Cy_SCB_SPI_Transfer(obj->base, (uint8_t *) tx, rx, xfr_length, &(obj->context));
while ( CY_SCB_SPI_TRANSFER_ACTIVE & Cy_SCB_SPI_GetTransferStatus(obj->base, &(obj->context))) { };
}
const uint8_t *bufptr = tx + (obj->data_bits <= 8 ? xfr_length : (xfr_length * 2));
Cy_SCB_SPI_Transfer(obj->base, (uint8_t *)bufptr, NULL, remaining_tx, &(obj->context));
while ( CY_SCB_SPI_TRANSFER_ACTIVE & Cy_SCB_SPI_GetTransferStatus(obj->base, &(obj->context))) { };
bufptr = obj->data_bits == 8 ?
(uint8_t *)(((uint8_t *)tx) + xfr_length) :
(uint8_t *)(((uint16_t *)tx) + xfr_length);
Cy_SCB_SPI_Transfer(obj->base, bufptr, NULL, remaining_tx, &(obj->context));
while ( CY_SCB_SPI_TRANSFER_ACTIVE & Cy_SCB_SPI_GetTransferStatus(obj->base, &(obj->context))) { };
}
}
else if (tx_length < rx_length)
{
xfr_length = (uint32_t) tx_length;
remaining_rx = (uint32_t) (rx_length - tx_length);
Cy_SCB_SPI_Transfer(obj->base, (uint8_t *) tx, rx, xfr_length, &(obj->context));
if (xfr_length != 0)
{
Cy_SCB_SPI_Transfer(obj->base, (uint8_t *) tx, rx, xfr_length, &(obj->context));
while ( CY_SCB_SPI_TRANSFER_ACTIVE & Cy_SCB_SPI_GetTransferStatus(obj->base, &(obj->context))) { };
while ( CY_SCB_SPI_TRANSFER_ACTIVE & Cy_SCB_SPI_GetTransferStatus(obj->base, &(obj->context))) { };
}
memset(dummy, write_fill, sizeof(dummy));
while (remaining_rx)
{
if (remaining_rx <= MAX_DUMMY_SIZE)
{
bufptr = obj->data_bits == 8 ?
(uint8_t *)(((uint8_t *)rx) + xfr_length) :
(uint8_t *)(((uint16_t *)rx) + xfr_length);
uint8_t *bufptr = rx + (obj->data_bits <= 8 ? xfr_length : (xfr_length * 2));
if (remaining_rx <= MAX_DUMMY_SIZE)
{
Cy_SCB_SPI_Transfer(obj->base, dummy, bufptr, remaining_rx, &(obj->context));
remaining_rx = 0;
}
else
{
bufptr = obj->data_bits == 8 ?
(uint8_t *)(((uint8_t *)rx) + xfr_length) :
(uint8_t *)(((uint16_t *)rx) + xfr_length);
}
else
{
Cy_SCB_SPI_Transfer(obj->base, dummy, bufptr, MAX_DUMMY_SIZE, &(obj->context));
remaining_rx -= MAX_DUMMY_SIZE;
xfr_length += MAX_DUMMY_SIZE;
}
}
while ( CY_SCB_SPI_TRANSFER_ACTIVE & Cy_SCB_SPI_GetTransferStatus(obj->base, &(obj->context))) { };
while ( CY_SCB_SPI_TRANSFER_ACTIVE & Cy_SCB_SPI_GetTransferStatus(obj->base, &(obj->context))) { };
}
}
else
}
else if (tx_length != 0) // tx_length == rx_length
{
xfr_length = (uint32_t) tx_length;
Cy_SCB_SPI_Transfer(obj->base, (uint8_t *) tx, rx, xfr_length, &(obj->context));
while ( CY_SCB_SPI_TRANSFER_ACTIVE & Cy_SCB_SPI_GetTransferStatus(obj->base, &(obj->context))) { };
}
if (!obj->is_slave)
{
cyhal_reset_ssel(obj);
}
return CY_RSLT_SUCCESS;
}
cy_rslt_t cyhal_spi_transfer_async(cyhal_spi_t *obj, const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length)
{
cy_en_scb_spi_status_t spi_status;
uint8_t *bufptr;
if (NULL == obj)
{
@ -1137,24 +1130,21 @@ cy_rslt_t cyhal_spi_transfer_async(cyhal_spi_t *obj, const uint8_t *tx, size_t t
cyhal_set_ssel(obj);
obj->is_async = true;
/* Setup transfer */
if (tx_length > rx_length)
if (tx_length > rx_length)
{
if (rx_length > 0)
if (rx_length > 0)
{
/* I) write + read, II) write only */
obj->pending = PENDING_TX_RX;
obj->rx_buffer = NULL;
bufptr = obj->data_bits == 8 ?
(uint8_t *)(((uint8_t *)tx) + rx_length) :
(uint8_t *)(((uint16_t *)tx) + rx_length);
obj->tx_buffer = bufptr;
obj->tx_buffer = tx + (obj->data_bits <= 8 ? rx_length : (rx_length * 2));
obj->tx_buffer_size = tx_length - rx_length;
spi_status = Cy_SCB_SPI_Transfer(obj->base, (void *)tx, rx, rx_length, &obj->context);
}
else
}
else
{
/* I) write only */
obj->pending = PENDING_TX;
@ -1163,24 +1153,21 @@ cy_rslt_t cyhal_spi_transfer_async(cyhal_spi_t *obj, const uint8_t *tx, size_t t
spi_status = Cy_SCB_SPI_Transfer(obj->base, (void *)tx, NULL, tx_length, &obj->context);
}
}
else if (rx_length > tx_length)
}
else if (rx_length > tx_length)
{
if (tx_length > 0)
if (tx_length > 0)
{
/* I) write + read, II) read only */
obj->pending = PENDING_TX_RX;
bufptr = obj->data_bits == 8 ?
(uint8_t *)(((uint8_t *)rx) + tx_length) :
(uint8_t *)(((uint16_t *)rx) + tx_length);
obj->rx_buffer = bufptr;
obj->rx_buffer = rx + (obj->data_bits <= 8 ? tx_length : (tx_length * 2));
obj->rx_buffer_size = rx_length - tx_length;
obj->tx_buffer = NULL;
spi_status = Cy_SCB_SPI_Transfer(obj->base, (void *)tx, rx, tx_length, &obj->context);
}
else
}
else
{
/* I) read only. */
obj->pending = PENDING_RX;
@ -1189,8 +1176,8 @@ cy_rslt_t cyhal_spi_transfer_async(cyhal_spi_t *obj, const uint8_t *tx, size_t t
spi_status = Cy_SCB_SPI_Transfer(obj->base, NULL, rx, rx_length, &obj->context);
}
}
else
}
else
{
/* RX and TX of the same size: I) write + read. */
obj->pending = PENDING_TX_RX;

View File

@ -689,13 +689,6 @@ static uint32_t cyhal_uart_baud_perdif(uint32_t desired_baud, uint32_t actual_ba
return perdif;
}
static uint32_t cyhal_divider_value(uint32_t frequency)
{
CY_ASSERT(frequency != 0);
/* UARTs use peripheral clock */
return (((cy_PeriClkFreqHz) + (frequency / 2)) / frequency) - 1;
}
static uint8_t cyhal_uart_best_oversample(uint32_t baudrate)
{
uint8_t differences[UART_OVERSAMPLE_MAX + 1];
@ -704,7 +697,7 @@ static uint8_t cyhal_uart_best_oversample(uint32_t baudrate)
for(index = UART_OVERSAMPLE_MIN; index < UART_OVERSAMPLE_MAX + 1; index++)
{
divider = cyhal_divider_value(baudrate * index);
divider = cyhal_divider_value(baudrate * index, 0);
differences[index] = cyhal_uart_baud_perdif(baudrate, cyhal_uart_actual_baud(divider, index));
}
@ -736,7 +729,7 @@ cy_rslt_t cyhal_uart_baud(cyhal_uart_t *obj, uint32_t baudrate, uint32_t *actual
oversample_value = cyhal_uart_best_oversample(baudrate);
obj->config.oversample = oversample_value;
divider = cyhal_divider_value(baudrate * oversample_value);
divider = cyhal_divider_value(baudrate * oversample_value, 0);
/* Set baud rate */
if ((obj->clock.div_type == CY_SYSCLK_DIV_16_5_BIT) || (obj->clock.div_type == CY_SYSCLK_DIV_24_5_BIT))