Skip to content

PSoC 6 I2C and SPI driver updates #11101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions targets/TARGET_Cypress/TARGET_PSOC6/cy_i2c_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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");
}
}

Expand Down
15 changes: 10 additions & 5 deletions targets/TARGET_Cypress/TARGET_PSOC6/cy_spi_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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");
}
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 received;
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading