diff --git a/docs/design-documents/hal/0001-i2c-overhaul.md b/docs/design-documents/hal/0001-i2c-overhaul.md new file mode 100644 index 00000000000..e0d8d3cc31b --- /dev/null +++ b/docs/design-documents/hal/0001-i2c-overhaul.md @@ -0,0 +1,494 @@ +# I2C Design Document + + +## Description + +This update to the I2C HAL API is the first stage in an initiative to standardise and gain consistency across existing and future HAL APIs and their implementations. + +## Motivation + +Many of the current HAL API interfaces, including the I2C API, do not provide a clear, concrete specification to develop implementations against. As a result, the existing implementations lack consistency and do not have uniform behaviour across all partner boards. + +The inconsistencies in the current implementations due to poorly defined specifications are listed below, these will be fixed as part of this overhaul. + +As well as fixing existing inconsistencies there are a few unimplemented features that have been requested from the API, or unused features that have been overlooked, these will be added and removed respectively. + +Additionally, since the original implementations were added for the API a large number of additional boards have been supported, the overhaul to the API allows partners the opportunity to consolidate the implementations for a family of boards into a single implementation, which will reduce the development overhead in future if any changes are made down the line. + +### Inconsistencies + +- The implementation for `i2c_reset` varies across all platforms. + + The purpose of this function is to add a method of resetting the i2c bus. Most platform implementations do not implement this function correctly, either the implementation acts as a NOP and does nothing, or it calls `i2c_stop` which already has a functional representation in the API and is designed to perform a different action. + +- The implementation of the `i2c_start` and `i2c_stop` functions are not well defined. + + The return value of the function is not defined in the header file, the value has been left open to interpretation by the partner implementations, for example, some implementations return 0 on all conditions. Some implementations have added timeouts to the functionality of the function and return 1 on timeouts. This needs to be defined correctly to be uniform across all implementations. + +- The `i2c_slave_address` function has a parameter called `mask`, this parameter is listed as unused but some implementations use it to mask the `address` parameter. + + This parameter should be removed as it is not required by the API. It can be assumed that the address will be masked to exclude the read/write bit from the address, the behaviour of this does not need to change. + +- The `i2c_slave_address` function has a parameter called `idx`, this parameter is listed as unused but is utilised in some API implementations. + + This parameter is not required by the API, it should be removed to keep behaviour uniform across all platforms. + +- The implementation of the `i2c_byte_write` differs between platforms. + + The API documentation indicates that the return value should be 0 on success, 1 on NAK, 2 on timeout. Not all platforms return a value or handle a timeout. Some platforms return a completely different set of status, the Atmel implementation returns an `I2C_ERROR ` which does not map to the documented return value. + +- The return value of the `i2c_start` and `i2c_stop` functions are not documented. + + The function returns an integer but there is no documentation to suggest what the return value should be. Some implementations return 0 in all cases, and some use it to return error values, if this function is to return a value, the values should be standardised. + +- Some platforms overload the `i2c_slave_read`, `i2c_slave_write`, `i2c_read`, and `i2c_write` return values with statuses that aren't documented. + + These functions are documented to return the number of bytes written or read. Some implementations will return a non-zero value if the write/read fails, this is not documented anywhere and the behaviour is not common across all implementations. + +- Some platforms overload the `i2c_read` and `i2c_write` return values with statuses that aren't documented. + + The functions are documented to return the number of bytes written or read. Some implementations will return a non-zero value if the write/read fails, this is not documented anywhere and the behaviour is not common across all implementations. + +- `i2c_master_transfer` takes a `uint32_t` instead of a function pointer type for its `handler` argument. + +- `i2c_slave_receive` should return an enumeration of the slave mode, currently it returns one of 4 integers depending on what mode the peripheral is in, this is much more suited to an enumeration. + +- The behaviour of the `stop` parameter in `i2c_write` is not consistent across platforms. + + The parameter is intended to issue the `STOP` command when a transfer has finished. Not all platforms use this bit, some platforms ignore the argument and either always issue a `STOP` command, or never. This parameter should be removed, there is already a means to call `STOP`. + +- The behaviour of the I2C peripheral is not uniform in multimaster configurations. There are no specifications indicating what a device should do when needs to handle collision or arbitration loss due to other master devices sharing the bus. Some platforms will transparently handle arbitration and others will return an error to the user API, and some do not handle multimaster. + +## Use cases + +List of drivers and examples currently using the I2C interface: + +* [I2C EEPROM Driver](https://github.com/ARMmbed/i2cee-driver) + +### Other use cases + +- I2C Slave + + In this use case the peripheral receives the clock instead of generating it and responds when addressed by the master. + +- I2C Async + + These are basically the same the regular ones except that the function call should return immediately and a callback should be triggered once the operation is completed. + +- I2C MultiMaster + + The I2C specification defines I2C as a multimaster bus. This allows multiple I2C devices in master mode to concurrently control a slave device on the same bus. The requirements on the master hardware is the ability to handle transfer collisions when both devices attempt to communicate with the slave simultaneously. + +## API changes + +### General changes + +- **Add** an `i2c_free` function to the API. + + All new HAL APIs must provide a free function to act as a destructor so that the resources used by the i2c instance can be reused. This is useful for OOP functionality in the platform API, and potentially reducing power consumption through the freeing of resources. + +- **Add** `i2c_timeout` function to the API. + + The timeout value is used when a slave attached to the master is clock stretching. The timeout value is used to specify the maximum period of time that the master peripheral will wait for the slave to release the SCL line. This timeout duration is not currently configurable, adding this function will allow this to be set to a specific period before failing the transfer with a timeout error. + +- **Add** an `i2c_get_capabilities` function to API return supported capabilities and constraints on the currently running platform. + +- **Add** specification enforcing multimaster support on platforms that support it. Not all partner boards support multimaster, any platform that does support it must handle arbitration with other masters on the same bus transparently to the user and API. + +- **Remove** `i2c_reset` function from the API. + + Most target implementations do not implement this function correctly. Most implementations invoke the `stop` command, or directly call the `i2c_stop` from this function which already has a function associated with it in the API. This function is not implemented by the user facing platform API so this change does not affect users. + +- **Change** the `frequency` parameter of `i2c_frequency` from `int` to `uint32_t`. + + Frequency should be unsigned as a signed value does not make sense in this context. `int` also does not have a guaranteed size. + +- **Add** a return value to the `i2c_frequency` which indicates the frequency that the peripheral was configured to. + + The frequency requested may not be supported by the I2C peripheral, the peripheral will select the nearest supported frequency instead, this selected frequency will be returned to inform the caller of the difference. + +- **Change** the `stop` parameter for the transfer function from an `int` value to a `bool` value. + + This function argument does not make sense as an `int` value other than for outdated compatibility reasons, the `bool` value expresses the intent more accurately. + + +### Sync API changes + +The main changes involve the removal of the single byte read/write functions and rolling their functionality into the block read/write functions, removing unnecessary parameters from functions and amending their types. + +- **Remove** the `stop` parameter from `i2c_write` and `i2c_read` functions. + + This parameter is not required, the STOP command should be sent manually by calling `i2c_stop` this reduces the amount of conditions that implementations have to meet. + +- **Remove** the `i2c_byte_read` and `i2c_byte_write` functions from the API and integrate the functionality into `i2c_read` and `i2c_write`. + + The functionality of these calls can be implemented as part of the normal `i2c_read` and `i2c_write` functions. Sending individual bytes of data is inefficient and should be avoided where possible. + +- **Change** the `address` parameter in `i2c_write` and `i2c_read` functions from `int` to `uint16_t`. + + The address parameter is up to a 9-bit value, specifying a type with correct sign and size is sensible. + +- **Remove** the return values from `i2c_start` and `i2c_stop` + + Most platforms cannot detect failure at this point and a return status does not make sense at this point. + +- **Change** the `length` parameter in `i2c_write` and `i2c_read` functions from `int` to `uint32_t`. + + The length parameter cannot be signed. + +- **Change** the `data` parameter in `i2c_write` and `i2c_read` functions from `char*` to `void*`. + +### Slave API changes + +The main changes involve removing the slave specific read/write functions and rolling them into the normal read/write functions, removing most of the slave configuration which can be handled at construction by the `init` function. + +- **Remove** the `i2c_slave_mode` function, add an `is_slave` parameter to the `i2c_init` function. + + The decision to initialise the peripheral in master or slave mode should be decided at construction time. This simplifies the API as it removes the need for two separate functions to initialise slave mode `i2c_slave_mode` and `i2c_slave_address` . + +- **Remove** the `i2c_slave_address` function, add an `address` parameter to the `i2c_init` function. + + The decision to initialise the I2C peripheral in master or slave mode should be decided at construction time. Adding the `address` parameter removes the need to initialise the address separately. This parameter is ignored if the `is_slave` Boolean is not set. + +- **Remove** the I2C slave specific transfer functions: `i2c_slave_read`, `i2c_slave_write`. + + These functions are superfluous and can be rolled into the existing `i2c_read` and `i2c_write` functions. The `transfer` function will execute the slave read/write based on the current configuration of the peripheral. + +- **Change** the return type of `i2c_slave_receive` from an integer to an enumeration. + + The function returns which mode the peripheral is currently operating in as an integer, this is better expressed as an enumeration. + +### Async API changes + +- **Remove** the `DMAUsage` argument for asynchronous transfers. + + Currently the `DMAUsage` argument of the `i2c_transfer_asynch` function is unimplemented, the argument is unused by all `I2C` implementations. There is no real demand for it so can be removed from the API. + +- **Change** the `stop` parameter from the `i2c_transfer_async` from an `uint32_t` to a `bool`. + + The stop parameter indicates whether or not the function should send a `STOP` command after the transfer has complete, there is no reason at all for this to be a `uint32_t`. + +- **Change** the return type of `i2c_transfer_asynch` to indicate whether or not a transfer has been scheduled or not. + + The function now returns a `bool` indicate if a transfer was scheduled or not, which can occur if the peripheral is already busy. + +- **Remove** the `i2c_irq_handler_asynch` function from the API. + + The event is now passed as an argument to the callback this method is no longer required. + +- **Remove** the `event` parameter from the `i2c_transfer_async` function. + + The callback will now be invoked on any event with the event as an argument. + +- **Remove** the `i2c_active` function from the API. + + The the async callback is now always invoked on async operation termination (unless cancelled), this status can be tracked from driver layer without any HAL request. + +### The new API + +```c++ +typedef struct { + /**< Minimum frequency supported must be set by target device */ + uint32_t minimum_frequency; + /**< Maximum frequency supported must be set by target device */ + uint32_t maximum_frequency; + /**< If true, the device can handle I2C slave mode. */ + bool supports_slave_mode; + /**< If true, supports 10-bit addressing. */ + bool supports_10bit_addressing; + /**< If true, the device handle multimaster collisions and arbitration safely*/ + bool supports_multi_master; + /**< If true, supports configuring clock stretching. */ + bool supports_clock_stretching; +} i2c_capabilities_t; + +/** Fills structure indicating supported features and frequencies on the current + * platform. + * + * @param[out] capabilities Capabilities structure filled with supported + * configurations. + */ +void i2c_get_capabilities(i2c_capabilities_t *capabilities); + +/** Initialize the I2C peripheral. It sets the default parameters for I2C + * peripheral, and configures its pins. + * + * @param obj The I2C object + * @param sda The sda pin + * @param scl The scl pin + * @param is_slave Choose whether the peripheral is initialised as master or + * slave. + */ +void i2c_init(i2c_t *obj, PinName sda, PinName scl, bool is_slave); + +/** Release the I2C object. + * + * @param obj The I2C object + */ +void i2c_free(i2c_t *obj); + +/** Configure the frequency in Hz the I2C peripheral should operate at. + * + * @param obj The I2C object + * @param frequency Frequency in Hz + * + * @returns The actual frequency that the peripheral will be generating to + * allow a user adjust its strategy in case the target cannot be + * reached. + */ +uint32_t i2c_frequency(i2c_t *obj, uint32_t frequency); + + +/** Configure the timeout duration in milliseconds the I2C peripheral should + * allow the slave peripheral to stretch the clock for before timing out. + * + * @param obj The I2C object + * @param timeout Clock stretching timeout in milliseconds. + */ +void i2c_timeout(i2c_t *obj, uint32_t timeout); + +/** Send START command + * + * @param obj The I2C object + */ +void i2c_start(i2c_t *obj); + +/** Send STOP command + * + * @param obj The I2C object + */ +void i2c_stop(i2c_t *obj); + +/** Blocking sending data + * + * This function transmits data, when the peripheral is configured as Master to + * the selected slave, and when configured as Slave transmits data to the + * Master. + * + * This function is blocking, it will return when the transfer is complete or a + * timeout event is triggered. The number of bytes transmitted is returned by + * the function after the operation is completed. Transmit operation cannot be + * cancelled or aborted. + * + * The data buffer must stay allocated during the duration of the transfer and + * the contents must not be modified. The value of the specified `address` is + * ignored when configured in slave mode, in master mode it contains the + * address of the target peripheral. This is a 7-bit value unless 10-bit + * addressing is configured and supported by the target. + * + * When in master mode the operation consists of: + * - Address the slave as a Master transmitter. + * - Transmit data to the addressed slave. + * - Generate a STOP condition if the specified `stop` field is true. + * + * @param obj The I2C object + * @param address 7-bit address (last bit is 0) + * @param data The buffer for sending + * @param length Number of bytes to write + * @param stop If true, stop will be generated after the transfer is done + * + * @note If the current platform supports multimaster operation the transfer + * will block until the peripheral can gain arbitration of the bus and + * complete the transfer. If the device does not support multimaster + * operation this function is not safe to execute when the bus is shared + * with another device in master mode. + * + * @return + * zero or non-zero - Number of written bytes + * negative - I2C_ERROR_XXX status + */ +int32_t i2c_write(i2c_t *obj, uint16_t address, const void *data, uint32_t length, bool stop); + +/** Blocking reading data + * + * This function receives data, when the peripheral is configured as Master + * from the selected slave, and when configured as Slave from the Master. + * + * This function is blocking, it will return when the transfer is complete or a + * timeout event is triggered. The number of bytes received is returned by + * the function after the operation is completed. Receive operation cannot be + * cancelled or aborted. + * + * When in master mode the operation consists of: + * - Address the slave as a Master receiver. + * - Receive data from the addressed slave. + * - Generate a STOP condition if the specified `stop` field is true. + * + * @param obj The I2C object + * @param address 7-bit address (last bit is 1) + * @param data The buffer for receiving + * @param length Number of bytes to read + * @param stop If true, stop will be generated after the transfer is done + * + * @note If the current platform supports multimaster operation the transfer + * will block until the peripheral can gain arbitration of the bus and + * complete the transfer. If the device does not support multimaster + * operation this function is not safe to execute when the bus is shared + * with another device in master mode. + * + * @return + * zero or non-zero - Number of written bytes + * negative - I2C_ERROR_XXX status + */ +int32_t i2c_read(i2c_t *obj, uint16_t address, void *data, uint32_t length, bool stop); + +typedef enum { + NoData = 0, // Slave has not been addressed. + ReadAddressed = 1, // Master has requested a read from this slave. + WriteGeneral = 2, // Master is writing to all slaves. + WriteAddressed = 3 // Master is writing to this slave. +} i2c_slave_status_t; + +/** Check to see if the I2C slave has been addressed. + * @param obj The I2C object + * @return The status - i2c_slave_status_t indicating what mode the peripheral + * is configured in. + */ +i2c_slave_status_t i2c_slave_status(i2c_t *obj); + +/** Configure I2C address. + * + * @note This function does nothing when configured in master mode. + * + * @param obj The I2C object + * @param address The address to be set + */ +void i2c_slave_address(i2c_t *obj, uint16_t address); + +typedef void (*i2c_async_handler_f)(i2c_t *obj, void *ctx, i2c_async_event_t event); + +/** Start I2C asynchronous transfer + * + * @param obj The I2C object + * @param tx The transmit buffer + * @param tx_length The number of bytes to transmit + * @param rx The receive buffer + * @param rx_length The number of bytes to receive + * @param address The address to be set - 7bit or 9bit + * @param stop If true, stop will be generated after the transfer is done + * @param handler The I2C IRQ handler to be set + */ +void i2c_transfer_async(i2c_t *obj, const void *tx, uint32_t tx_length, + void *rx, uint32_t rx_length, uint16_t address, + bool stop, i2c_async_handler_f handler, void *ctx); + +/** Abort asynchronous transfer + * + * This function does not perform any check - that should happen in upper + * layers. + * + * @param obj The I2C object + */ +void i2c_abort_async(i2c_t *obj); +``` + +## Behaviours + +### Defined behaviours + +- `i2c_init`: + - Initialises the peripheral pins specified in the input parameters. + - Initialises the peripheral in master mode if `is_slave` is false. + - Initialises the peripheral in slave mode if `is_slave` is true and `supports_slave_mode` is true. +- `i2c_free`: + - Resets the pins used to initialise the peripheral to their default state. + - Disables the peripheral clock. +- `i2c_get_capabilities`: + - Fills the contents of the `i2c_capabilities_t` parameter +- `i2c_frequency`: + - Returns the actual frequency that will be used. + - Sets the frequency to use for the transfer. + - Must leave all other configuration unchanged. +- `i2c_timeout`: + - Sets the clock stretching timeout to use for the following transfers. + - If the timeout is set to 0, disables clock stretching. +- `i2c_write`: + - Writes `length` number of symbols to the bus. + - Returns the number of symbols sent to the bus. + - Returns an error status if transfer fails. + - Generates a stop condition on the bus at the end of the transfer if `stop` parameter is true. + - Handles transfer collisions and loss of arbitration if the platform supports multimaster in hardware. + - The transfer will timeout and return `I2C_ERROR_TIMEOUT ` if the slave stretches the clock for longer than the configured timeout duration. +- `i2c_read`: + - Reads `rx_len` symbols from the bus. + - Returns the number of symbols received from the bus. + - Returns an error code if transfer fails. + - Handles transfer collisions and loss of arbitration if the platform supports multimaster in hardware. + - The transfer will timeout and return `I2C_ERROR_TIMEOUT ` if the slave stretches the clock for longer than the configured timeout duration. +- `i2c_start`: + - Generates I2C START condition on the bus in master mode. + - Does nothing if called when the peripheral is configured in slave mode. +- `i2c_stop`: + - Generates I2C STOP condition on the bus in master mode. + - Does nothing if called when the peripheral is configured in slave mode. +- `i2c_slave_receive`: + - Indicates which mode the peripheral has been addressed in. + - Returns not addressed when called in master mode. +- `i2c_slave_address`: + - Sets the address of the peripheral to the `address` parameter. + - Does nothing if called master mode. +- `i2c_transfer_async`: + - Returns immediately with a `bool` indicating whether the transfer was successfully scheduled or not. + - The callback given to `i2c_transfer_async` is invoked when the transfer finishes. + - Must save the handler and context pointers inside the `obj` pointer. + - The context pointer is passed to the callback on transfer completion. + - The callback must be invoked on completion unless the transfer is aborted. + - `i2c_async_event_t` must be filled with the number of symbols sent to the bus during transfer. +- `i2c_abort_async`: + - Aborts any on-going async transfers. + +### Undefined behaviours + +- Use of a `null` pointer as an argument to any function. +- Calling any `I2C` function before calling `i2c_init` or after calling `i2c_free`. +- Initialising the `I2C` peripheral with invalid `SDA` and `SCL` pins. +- Initialising the peripheral in slave mode if slave mode is not supported, indicated by `i2c_get_capabilities`. +- Operating the peripheral in slave mode without first specifying and address using `i2c_address` +- Setting an address using `i2c_address` after initialising the peripheral in master mode. +- Setting an address to an `I2C` reserved value. +- Setting an address larger than the 7-bit supported maximum if 10-bit addressing is not supported. +- Setting an address larger than the 10-bit supported maximum. +- Setting a frequency outside the supported range given by `i2c_get_capabilities` +- Using the device in a multimaster configuration when `supports_multimaster_mode` is false. +- Setting the timeout outside the supported range given by `i2c_get_capabilities`. +- Specifying an invalid address when calling any `read` or `write` functions. +- Setting the length of the transfer or receive buffers to larger than the buffers are. +- Passing an invalid pointer as `handler` to `i2c_transfer_async`. +- Calling `i2c_transfer_abort` when no transfer is currently in progress. + +## Impact on Partner implementations + +For each target implementation the existing API must be refactored or reimplemented to conform to the updated API. Given that many partners have a single implementation for each board family, generally only one target will need to be updated per partner. + +- STM32 - No implementations: 1 + + There is a single I2C implementation that implements the interface for all partner boards. Updating the implementation to match the new API will require a single rewrite of this implementation, though ensuring the changes work without regressions on all of the boards may be difficult. + +- K64F - No implementations: 3 + + There are three implementations for I2C. One for `K20` family boards, one for `KL` family boards, and one for `MCUX` boards. All three implementations would require rewriting for the new API. + +- NORDIC - No implementations: 2 + + There are two implementations one for `NRF5*` family boards, and one specifically for `NRF51822`. There doesn't seem to be an apparent reason why these couldn't be unified into a single implementation when the API is updated. + +- Atmel - No implementations: 2 + + One implementation for `M0+` family boards, another implementation for `M4` boards. + +- Silicon Labs - No implementations: 1 + + A single implementation for all boards, only a single update required. + +- Maxim - No implementation 6 + + There are 6 instances of the `i2c_api` driver, only 3 of these are unique and the rest are copies in different folders so realistically only 3 updates are required. + + +## Drawbacks + +These are breaking changes to the API. The changes will require each partner to reimplement their current I2C drivers to conform with the updated API. + + +## FAQ + diff --git a/drivers/I2C.cpp b/drivers/I2C.cpp index 3e06825c17d..17a059f434a 100644 --- a/drivers/I2C.cpp +++ b/drivers/I2C.cpp @@ -32,7 +32,7 @@ SingletonPtr I2C::_mutex; I2C::I2C(PinName sda, PinName scl) : #if DEVICE_I2C_ASYNCH - _irq(this), _usage(DMA_USAGE_NEVER), _deep_sleep_locked(false), + _irq(this), _deep_sleep_locked(false), #endif _i2c(), _hz(100000) { @@ -41,7 +41,9 @@ I2C::I2C(PinName sda, PinName scl) : _sda = sda; _scl = scl; recover(sda, scl); - i2c_init(&_i2c, _sda, _scl); + i2c_init(&_i2c, sda, scl, false); + i2c_frequency(&_i2c, _hz); + // Used to avoid unnecessary frequency updates _owner = this; unlock(); @@ -50,7 +52,7 @@ I2C::I2C(PinName sda, PinName scl) : void I2C::frequency(int hz) { lock(); - _hz = hz; + _hz = (uint32_t)hz; // We want to update the frequency even if we are already the bus owners i2c_frequency(&_i2c, _hz); @@ -77,7 +79,7 @@ int I2C::write(int address, const char *data, int length, bool repeated) aquire(); int stop = (repeated) ? 0 : 1; - int written = i2c_write(&_i2c, address, data, length, stop); + int written = i2c_write(&_i2c, address, (void *)data, length, stop); unlock(); return length != written; @@ -86,7 +88,7 @@ int I2C::write(int address, const char *data, int length, bool repeated) int I2C::write(int data) { lock(); - int ret = i2c_byte_write(&_i2c, data); + int ret = i2c_write(&_i2c, 0, (void *)&data, 1, false); unlock(); return ret; } @@ -108,11 +110,7 @@ int I2C::read(int ack) { lock(); int ret; - if (ack) { - ret = i2c_byte_read(&_i2c, 0); - } else { - ret = i2c_byte_read(&_i2c, 1); - } + i2c_read(&_i2c, 0, &ret, 1, (ack == 0)); unlock(); return ret; } @@ -191,40 +189,17 @@ int I2C::recover(PinName sda, PinName scl) int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t &callback, int event, bool repeated) { - lock(); - if (i2c_active(&_i2c)) { - unlock(); - return -1; // transaction ongoing - } - lock_deep_sleep(); - aquire(); - - _callback = callback; - int stop = (repeated) ? 0 : 1; - _irq.callback(&I2C::irq_handler_asynch); - i2c_transfer_asynch(&_i2c, (void *)tx_buffer, tx_length, (void *)rx_buffer, rx_length, address, stop, _irq.entry(), event, _usage); - unlock(); return 0; } void I2C::abort_transfer(void) { lock(); - i2c_abort_asynch(&_i2c); - unlock_deep_sleep(); unlock(); } void I2C::irq_handler_asynch(void) { - int event = i2c_irq_handler_asynch(&_i2c); - if (_callback && event) { - _callback.call(event); - } - - if (event) { - unlock_deep_sleep(); - } } void I2C::lock_deep_sleep() diff --git a/drivers/I2C.h b/drivers/I2C.h index 9a19bd12474..e501774ac7d 100644 --- a/drivers/I2C.h +++ b/drivers/I2C.h @@ -210,7 +210,6 @@ class I2C : private NonCopyable { void irq_handler_asynch(void); event_callback_t _callback; CThunk _irq; - DMAUsage _usage; bool _deep_sleep_locked; #endif #endif @@ -221,7 +220,7 @@ class I2C : private NonCopyable { i2c_t _i2c; static I2C *_owner; - int _hz; + uint32_t _hz; static SingletonPtr _mutex; PinName _sda; PinName _scl; diff --git a/drivers/I2CSlave.cpp b/drivers/I2CSlave.cpp index f0697460be6..0fcfd619e6e 100644 --- a/drivers/I2CSlave.cpp +++ b/drivers/I2CSlave.cpp @@ -22,9 +22,8 @@ namespace mbed { I2CSlave::I2CSlave(PinName sda, PinName scl) : _i2c() { - i2c_init(&_i2c, sda, scl); + i2c_init(&_i2c, sda, scl, true); i2c_frequency(&_i2c, 100000); - i2c_slave_mode(&_i2c, 1); } void I2CSlave::frequency(int hz) @@ -35,32 +34,36 @@ void I2CSlave::frequency(int hz) void I2CSlave::address(int address) { int addr = (address & 0xFF) | 1; - i2c_slave_address(&_i2c, 0, addr, 0); + + i2c_slave_address(&_i2c, addr); } int I2CSlave::receive(void) { - return i2c_slave_receive(&_i2c); + return i2c_slave_status(&_i2c); } int I2CSlave::read(char *data, int length) { - return i2c_slave_read(&_i2c, data, length) != length; + return i2c_read(&_i2c, 0, data, length, false) != length; } int I2CSlave::read(void) { - return i2c_byte_read(&_i2c, 0); + int ret; + i2c_read(&_i2c, 0, &ret, 1, false); + + return ret; } int I2CSlave::write(const char *data, int length) { - return i2c_slave_write(&_i2c, data, length) != length; + return i2c_write(&_i2c, 0, data, length, false) != length; } int I2CSlave::write(int data) { - return i2c_byte_write(&_i2c, data); + return i2c_write(&_i2c, 0, (void *)&data, 1, false); } void I2CSlave::stop(void) @@ -68,6 +71,6 @@ void I2CSlave::stop(void) i2c_stop(&_i2c); } -} +} // namespace mbed -#endif +#endif // DEVICE_I2CSLAVE diff --git a/drivers/I2CSlave.h b/drivers/I2CSlave.h index 78715ba9345..1289b1fea08 100644 --- a/drivers/I2CSlave.h +++ b/drivers/I2CSlave.h @@ -154,6 +154,8 @@ class I2CSlave { #if !defined(DOXYGEN_ONLY) protected: + PinName _sda; + PinName _scl; /* Internal i2c object identifying the resources */ i2c_t _i2c; diff --git a/hal/i2c_api.h b/hal/i2c_api.h index 3ade94ce778..6ccf06a210d 100644 --- a/hal/i2c_api.h +++ b/hal/i2c_api.h @@ -28,6 +28,8 @@ #include "hal/dma_api.h" #endif +#include + #if DEVICE_I2C /** @@ -44,13 +46,26 @@ /**@}*/ #if DEVICE_I2C_ASYNCH + +typedef struct i2c i2c_t; + +typedef struct i2c_async_event { + uint32_t sent_bytes; + uint32_t received_bytes; + bool error; +} i2c_async_event_t; + +typedef void (*i2c_async_handler_f)(i2c_t *obj, i2c_async_event_t *event, void *ctx); + /** Asynch I2C HAL structure */ -typedef struct { - struct i2c_s i2c; /**< Target specific I2C structure */ +struct i2c { + struct i2c_s i2c; /**< Target specific I2C structure */ struct buffer_s tx_buff; /**< Tx buffer */ struct buffer_s rx_buff; /**< Rx buffer */ -} i2c_t; + i2c_async_handler_f handler; + void *ctx; +}; #else /** Non-asynch I2C HAL structure @@ -61,91 +76,170 @@ typedef struct i2c_s i2c_t; enum { I2C_ERROR_NO_SLAVE = -1, - I2C_ERROR_BUS_BUSY = -2 + I2C_ERROR_BUS_BUSY = -2, + I2C_ERROR_TIMEOUT = -3 }; #ifdef __cplusplus extern "C" { #endif +typedef struct { + /**< Minimum frequency supported must be set by target device */ + uint32_t minimum_frequency; + /**< Maximum frequency supported must be set by target device */ + uint32_t maximum_frequency; + /**< If true, the device can handle I2C slave mode. */ + bool supports_slave_mode; + /**< If true, supports 10-bit addressing. */ + bool supports_10bit_addressing; + /**< If true, the device handle multimaster collisions and arbitration safely*/ + bool supports_multi_master; + /**< If true, supports configuring clock stretching. */ + bool supports_clock_stretching; +} i2c_capabilities_t; + /** * \defgroup hal_GeneralI2C I2C Configuration Functions * @{ */ +/** Fills structure indicating supported features and frequencies on the current + * platform. + * + * @param[out] capabilities Capabilities structure filled with supported + * configurations. + */ +void i2c_get_capabilities(i2c_capabilities_t *capabilities); + /** Initialize the I2C peripheral. It sets the default parameters for I2C - * peripheral, and configures its specifieds pins. + * peripheral, and configures its pins. * - * @param obj The I2C object - * @param sda The sda pin - * @param scl The scl pin + * @param obj The I2C object + * @param sda The sda pin + * @param scl The scl pin + * @param is_slave Choose whether the peripheral is initialised as master or + * slave. */ -void i2c_init(i2c_t *obj, PinName sda, PinName scl); +void i2c_init(i2c_t *obj, PinName sda, PinName scl, bool is_slave); -/** Configure the I2C frequency +/** Release the I2C object. * * @param obj The I2C object - * @param hz Frequency in Hz */ -void i2c_frequency(i2c_t *obj, int hz); +void i2c_free(i2c_t *obj); -/** Send START command +/** Configure the frequency in Hz the I2C peripheral should operate at. * - * @param obj The I2C object + * @param obj The I2C object + * @param frequency Frequency in Hz + * + * @returns The actual frequency that the peripheral will be generating to + * allow a user adjust its strategy in case the target cannot be + * reached. */ -int i2c_start(i2c_t *obj); +uint32_t i2c_frequency(i2c_t *obj, uint32_t frequency); -/** Send STOP command +/** Enable or disable clock stretching for the I2C peripheral. * - * @param obj The I2C object + * The behaviour is undefined unless `obj` points to a valid 'i2c_t' object + * and the target supports configuring clock stretching, indicated by the + * 'supports_clock_stretching' attribute returned by the 'i2c_get_capabilities' + * function. + * + * @param obj The I2C object + * @param enabled If 'true' enable clock stretching on the given I2C peripheral, + * otherwise disable it. */ -int i2c_stop(i2c_t *obj); +void i2c_set_clock_stretching(i2c_t *obj, const bool enabled); -/** Blocking reading data +/** Send START command * - * @param obj The I2C object - * @param address 7-bit address (last bit is 1) - * @param data The buffer for receiving - * @param length Number of bytes to read - * @param stop Stop to be generated after the transfer is done - * @return Number of read bytes + * @param obj The I2C object. */ -int i2c_read(i2c_t *obj, int address, char *data, int length, int stop); +void i2c_start(i2c_t *obj); + +/** Send STOP command + * + * @param obj The I2C object + */ +void i2c_stop(i2c_t *obj); /** Blocking sending data + * + * This function transmits data, when the peripheral is configured as Master to + * the selected slave, and when configured as Slave transmits data to the + * Master. + * + * This function is blocking, it will return when the transfer is complete or a + * timeout event is triggered. The number of bytes transmitted is returned by + * the function after the operation is completed. Transmit operation cannot be + * cancelled or aborted. + * + * The data buffer must stay allocated during the duration of the transfer and + * the contents must not be modified. The value of the specified `address` is + * ignored when configured in slave mode, in master mode it contains the + * address of the target peripheral. This is a 7-bit value unless 10-bit + * addressing is configured and supported by the target. + * + * When in master mode the operation consists of: + * - Address the slave as a Master transmitter. + * - Transmit data to the addressed slave. + * - Generate a STOP condition if the specified `stop` field is true. * * @param obj The I2C object * @param address 7-bit address (last bit is 0) * @param data The buffer for sending * @param length Number of bytes to write - * @param stop Stop to be generated after the transfer is done + * @param stop If true, stop will be generated after the transfer is done + * + * @note If the current platform supports multimaster operation the transfer + * will block until the peripheral can gain arbitration of the bus and + * complete the transfer. If the device does not support multimaster + * operation this function is not safe to execute when the bus is shared + * with another device in master mode. + * * @return * zero or non-zero - Number of written bytes * negative - I2C_ERROR_XXX status */ -int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop); +int32_t i2c_write(i2c_t *obj, uint16_t address, const void *data, + uint32_t length, bool stop); -/** Reset I2C peripheral. TODO: The action here. Most of the implementation sends stop() +/** Blocking reading data * - * @param obj The I2C object - */ -void i2c_reset(i2c_t *obj); - -/** Read one byte + * This function receives data, when the peripheral is configured as Master + * from the selected slave, and when configured as Slave from the Master. * - * @param obj The I2C object - * @param last Acknoledge - * @return The read byte - */ -int i2c_byte_read(i2c_t *obj, int last); - -/** Write one byte + * This function is blocking, it will return when the transfer is complete or a + * timeout event is triggered. The number of bytes received is returned by + * the function after the operation is completed. Receive operation cannot be + * cancelled or aborted. * - * @param obj The I2C object - * @param data Byte to be written - * @return 0 if NAK was received, 1 if ACK was received, 2 for timeout. + * When in master mode the operation consists of: + * - Address the slave as a Master receiver. + * - Receive data from the addressed slave. + * - Generate a STOP condition if the specified `stop` field is true. + * + * @param obj The I2C object + * @param address 7-bit address (last bit is 1) + * @param data The buffer for receiving + * @param length Number of bytes to read + * @param last If true, indicates that the transfer contains the last byte + * to be sent. + * + * @note If the current platform supports multimaster operation the transfer + * will block until the peripheral can gain arbitration of the bus and + * complete the transfer. If the device does not support multimaster + * operation this function is not safe to execute when the bus is shared + * with another device in master mode. + * + * @return + * zero or non-zero - Number of written bytes + * negative - I2C_ERROR_XXX status */ -int i2c_byte_write(i2c_t *obj, int data); +int32_t i2c_read(i2c_t *obj, uint16_t address, void *data, uint32_t length, + bool last); /** Get the pins that support I2C SDA * @@ -192,43 +286,28 @@ const PinMap *i2c_slave_scl_pinmap(void); * @{ */ -/** Configure I2C as slave or master. - * @param obj The I2C object - * @param enable_slave Enable i2c hardware so you can receive events with ::i2c_slave_receive - * @return non-zero if a value is available - */ -void i2c_slave_mode(i2c_t *obj, int enable_slave); +typedef enum { + NoData = 0, // Slave has not been addressed. + ReadAddressed = 1, // Master has requested a read from this slave. + WriteGeneral = 2, // Master is writing to all slaves. + WriteAddressed = 3 // Master is writing to this slave. +} i2c_slave_status_t; /** Check to see if the I2C slave has been addressed. * @param obj The I2C object - * @return The status - 1 - read addresses, 2 - write to all slaves, - * 3 write addressed, 0 - the slave has not been addressed - */ -int i2c_slave_receive(i2c_t *obj); - -/** Configure I2C as slave or master. - * @param obj The I2C object - * @param data The buffer for receiving - * @param length Number of bytes to read - * @return non-zero if a value is available - */ -int i2c_slave_read(i2c_t *obj, char *data, int length); - -/** Configure I2C as slave or master. - * @param obj The I2C object - * @param data The buffer for sending - * @param length Number of bytes to write - * @return non-zero if a value is available + * @return The status - i2c_slave_status_t indicating what mode the peripheral + * is configured in. */ -int i2c_slave_write(i2c_t *obj, const char *data, int length); +i2c_slave_status_t i2c_slave_status(i2c_t *obj); /** Configure I2C address. + * + * @note This function does nothing when configured in master mode. + * * @param obj The I2C object - * @param idx Currently not used * @param address The address to be set - * @param mask Currently not used */ -void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask); +void i2c_slave_address(i2c_t *obj, uint16_t address); #endif @@ -251,31 +330,19 @@ void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask); * @param address The address to be set - 7bit or 9bit * @param stop If true, stop will be generated after the transfer is done * @param handler The I2C IRQ handler to be set - * @param event Event mask for the transfer. See \ref hal_I2CEvents - * @param hint DMA hint usage */ -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); - -/** The asynchronous IRQ handler - * - * @param obj The I2C object which holds the transfer information - * @return Event flags if a transfer termination condition was met, otherwise return 0. - */ -uint32_t i2c_irq_handler_asynch(i2c_t *obj); - -/** Attempts to determine if the I2C peripheral is already in use - * - * @param obj The I2C object - * @return Non-zero if the I2C module is active or zero if it is not - */ -uint8_t i2c_active(i2c_t *obj); +void i2c_transfer_async(i2c_t *obj, const void *tx, uint32_t tx_length, + void *rx, uint32_t rx_length, uint16_t address, + bool stop, i2c_async_handler_f handler, void *ctx); /** Abort asynchronous transfer * - * This function does not perform any check - that should happen in upper layers. + * This function does not perform any check - that should happen in upper + * layers. + * * @param obj The I2C object */ -void i2c_abort_asynch(i2c_t *obj); +void i2c_abort_async(i2c_t *obj); #endif diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c index ff6fc2a856d..2839dcbc6b7 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c @@ -25,223 +25,230 @@ #include "peripheral_clock_defines.h" #include "PeripheralPins.h" -/* 7 bit IIC addr - R/W flag not included */ -static int i2c_address = 0; /* Array of I2C peripheral base address. */ static I2C_Type *const i2c_addrs[] = I2C_BASE_PTRS; /* Array of I2C bus clock frequencies */ static clock_name_t const i2c_clocks[] = I2C_CLOCK_FREQS; -void i2c_init(i2c_t *obj, PinName sda, PinName scl) +void i2c_get_capabilities(i2c_capabilities_t *capabilities) { - uint32_t i2c_sda = pinmap_peripheral(sda, PinMap_I2C_SDA); - uint32_t i2c_scl = pinmap_peripheral(scl, PinMap_I2C_SCL); - PORT_Type *port_addrs[] = PORT_BASE_PTRS; - PORT_Type *base = port_addrs[sda >> GPIO_PORT_SHIFT]; + if (capabilities == NULL) { + return; + } + + capabilities->minimum_frequency = 1; + capabilities->maximum_frequency = 1000000; + capabilities->supports_slave_mode = false; + capabilities->supports_10bit_addressing = false; + capabilities->supports_multi_master = true; + capabilities->supports_clock_stretching = false; +} + +void i2c_init(i2c_t *obj, PinName sda, PinName scl, bool is_slave) +{ + uint32_t i2c_sda = pinmap_peripheral(sda, PinMap_I2C_SDA); + uint32_t i2c_scl = pinmap_peripheral(scl, PinMap_I2C_SCL); + + PORT_Type *port_addrs[] = PORT_BASE_PTRS; + PORT_Type *base = port_addrs[sda >> GPIO_PORT_SHIFT]; + + obj->instance = pinmap_merge(i2c_sda, i2c_scl); + obj->next_repeated_start = 0; + obj->is_slave = is_slave; + + MBED_ASSERT((int)obj->instance != NC); - obj->instance = pinmap_merge(i2c_sda, i2c_scl); - obj->next_repeated_start = 0; - MBED_ASSERT((int)obj->instance != NC); + const uint32_t clock_frequency = CLOCK_GetFreq(i2c_clocks[obj->instance]); + if (is_slave) { + i2c_slave_config_t slave_config; + + I2C_SlaveGetDefaultConfig(&slave_config); + slave_config.slaveAddress = 0; + slave_config.enableSlave = true; + +#if FSL_I2C_DRIVER_VERSION > MAKE_VERSION(2, 0, 1) + I2C_SlaveInit(i2c_addrs[obj->instance], &slave_config, clock_frequency); +#else + I2C_SlaveInit(i2c_addrs[obj->instance], &slave_config); +#endif + } else { i2c_master_config_t master_config; I2C_MasterGetDefaultConfig(&master_config); - I2C_MasterInit(i2c_addrs[obj->instance], &master_config, CLOCK_GetFreq(i2c_clocks[obj->instance])); - I2C_EnableInterrupts(i2c_addrs[obj->instance], kI2C_GlobalInterruptEnable); + master_config.enableMaster = true; - pinmap_pinout(sda, PinMap_I2C_SDA); - pinmap_pinout(scl, PinMap_I2C_SCL); + I2C_MasterInit(i2c_addrs[obj->instance], &master_config, clock_frequency); + I2C_EnableInterrupts(i2c_addrs[obj->instance], kI2C_GlobalInterruptEnable); + } - /* Enable internal pullup resistor */ - base->PCR[sda & 0xFF] |= (PORT_PCR_PE_MASK | PORT_PCR_PS_MASK); - base->PCR[scl & 0xFF] |= (PORT_PCR_PE_MASK | PORT_PCR_PS_MASK); + pinmap_pinout(sda, PinMap_I2C_SDA); + pinmap_pinout(scl, PinMap_I2C_SCL); #if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN - base->PCR[sda & 0xFF] |= PORT_PCR_ODE_MASK; - base->PCR[scl & 0xFF] |= PORT_PCR_ODE_MASK; + base->PCR[sda & 0xFF] |= PORT_PCR_ODE_MASK; + base->PCR[scl & 0xFF] |= PORT_PCR_ODE_MASK; +#else + /* Enable internal pullup resistor */ + base->PCR[sda & 0xFF] |= (PORT_PCR_PE_MASK | PORT_PCR_PS_MASK); + base->PCR[scl & 0xFF] |= (PORT_PCR_PE_MASK | PORT_PCR_PS_MASK); #endif } -int i2c_start(i2c_t *obj) +void i2c_free(i2c_t *obj) { - I2C_Type *base = i2c_addrs[obj->instance]; - uint32_t statusFlags = I2C_MasterGetStatusFlags(base); + I2C_Type *base = i2c_addrs[obj->instance]; - /* Check if the bus is already in use. */ - if (statusFlags & kI2C_BusBusyFlag) { - /* Send a repeat START signal. */ - base->C1 |= I2C_C1_RSTA_MASK; - } else { - /* Send the START signal. */ - base->C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK; - } + if (obj->is_slave) { + I2C_SlaveDeinit(base); + } else { + I2C_MasterDeinit(base); + } +} + +void i2c_start(i2c_t *obj) +{ + I2C_Type *base = i2c_addrs[obj->instance]; + + const uint32_t statusFlags = I2C_MasterGetStatusFlags(base); + + /* Check if the bus is already in use. */ + if ((statusFlags & kI2C_BusBusyFlag) != 0) { + /* Send a repeat START signal. */ + base->C1 |= I2C_C1_RSTA_MASK; + } else { + /* Send the START signal. */ + base->C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK; + } #if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING - while (!(base->S2 & I2C_S2_EMPTY_MASK)) - { - } + while (!(base->S2 & I2C_S2_EMPTY_MASK)) + { + } #endif /* FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING */ - - return 0; } -int i2c_stop(i2c_t *obj) +void i2c_stop(i2c_t *obj) { - if (I2C_MasterStop(i2c_addrs[obj->instance]) != kStatus_Success) { - return 1; - } + I2C_Type *base = i2c_addrs[obj->instance]; - return 0; + I2C_MasterStop(base); } -void i2c_frequency(i2c_t *obj, int hz) +uint32_t i2c_frequency(i2c_t *obj, uint32_t frequency) { - uint32_t busClock; + I2C_Type *base = i2c_addrs[obj->instance]; - busClock = CLOCK_GetFreq(i2c_clocks[obj->instance]); - I2C_MasterSetBaudRate(i2c_addrs[obj->instance], hz, busClock); -} + const uint32_t busClock = CLOCK_GetFreq(i2c_clocks[obj->instance]); -int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) -{ - I2C_Type *base = i2c_addrs[obj->instance]; - i2c_master_transfer_t master_xfer; - - i2c_address = address >> 1; - memset(&master_xfer, 0, sizeof(master_xfer)); - master_xfer.slaveAddress = address >> 1; - master_xfer.direction = kI2C_Read; - master_xfer.data = (uint8_t *)data; - master_xfer.dataSize = length; - if (obj->next_repeated_start) { - master_xfer.flags |= kI2C_TransferRepeatedStartFlag; - } - if (!stop) { - master_xfer.flags |= kI2C_TransferNoStopFlag; - } - obj->next_repeated_start = master_xfer.flags & kI2C_TransferNoStopFlag ? 1 : 0; + I2C_MasterSetBaudRate(base, frequency, busClock); - /* The below function will issue a STOP signal at the end of the transfer. - * This is required by the hardware in order to receive the last byte - */ - if (I2C_MasterTransferBlocking(base, &master_xfer) != kStatus_Success) { - return I2C_ERROR_NO_SLAVE; - } + return frequency; +} - return length; +void i2c_set_clock_stretching(i2c_t *obj, const bool enabled) +{ + (void)obj; + (void)enabled; } -int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) +static int i2c_block_read(i2c_t *obj, uint16_t address, void *data, uint32_t length, bool last) { - I2C_Type *base = i2c_addrs[obj->instance]; - i2c_master_transfer_t master_xfer; - - if (length == 0) { - if (I2C_MasterStart(base, address >> 1, kI2C_Write) != kStatus_Success) { - return I2C_ERROR_NO_SLAVE; - } - - while (!(base->S & kI2C_IntPendingFlag)) { - } - - base->S = kI2C_IntPendingFlag; - - if (base->S & kI2C_ReceiveNakFlag) { - i2c_stop(obj); - return I2C_ERROR_NO_SLAVE; - } else { - i2c_stop(obj); - return length; - } - } + I2C_Type *base = i2c_addrs[obj->instance]; - memset(&master_xfer, 0, sizeof(master_xfer)); - master_xfer.slaveAddress = address >> 1; - master_xfer.direction = kI2C_Write; - master_xfer.data = (uint8_t *)data; - master_xfer.dataSize = length; - if (obj->next_repeated_start) { - master_xfer.flags |= kI2C_TransferRepeatedStartFlag; - } - if (!stop) { - master_xfer.flags |= kI2C_TransferNoStopFlag; - } - obj->next_repeated_start = master_xfer.flags & kI2C_TransferNoStopFlag ? 1 : 0; + i2c_master_transfer_t transfer; + memset(&transfer, 0, sizeof(transfer)); + transfer.slaveAddress = (address >> 1); + transfer.direction = kI2C_Read; + transfer.data = (uint8_t *)data; + transfer.dataSize = length; - if (I2C_MasterTransferBlocking(base, &master_xfer) != kStatus_Success) { - return I2C_ERROR_NO_SLAVE; - } + if (obj->next_repeated_start) + transfer.flags |= kI2C_TransferRepeatedStartFlag; - return length; -} + if (!last) + transfer.flags |= kI2C_TransferNoStopFlag; -void i2c_reset(i2c_t *obj) -{ - i2c_stop(obj); + obj->next_repeated_start = (transfer.flags & kI2C_TransferNoStopFlag) ? 1 : 0; + + // The below function will issue a STOP signal at the end of the transfer. + // This is required by the hardware in order to receive the last byte + if (I2C_MasterTransferBlocking(base, &transfer) != kStatus_Success) + return I2C_ERROR_NO_SLAVE; + + return length; } -int i2c_byte_read(i2c_t *obj, int last) +#if DEVICE_I2CSLAVE + +static int i2c_slave_read(i2c_t *obj, void *data, uint32_t length) { - uint8_t data; - I2C_Type *base = i2c_addrs[obj->instance]; + I2C_Type *base = i2c_addrs[obj->instance]; - /* Setup the I2C peripheral to receive data. */ + if (base->S & kI2C_AddressMatchFlag) { + /* Slave receive, master writing to slave. */ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + /* Read dummy to release the bus. */ + base->D; + } - if (last) { - base->C1 |= I2C_C1_TXAK_MASK; // NACK - } - - data = (base->D & 0xFF); + I2C_SlaveReadBlocking(base, (uint8_t *)data, length); - /* Change direction to Tx to avoid extra clocks. */ - base->C1 |= I2C_C1_TX_MASK; + return length; +} - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) - { - } +i2c_slave_status_t i2c_slave_status(i2c_t *obj) +{ + uint32_t status_flags = I2C_SlaveGetStatusFlags(i2c_addrs[obj->instance]); - /* Clear the IICIF flag. */ - base->S = kI2C_IntPendingFlag; + if ((status_flags & kI2C_AddressMatchFlag) == 0) { + return NoData; + } - return data; + return ((status_flags & kI2C_TransferDirectionFlag) != 0) ? ReadAddressed + : WriteAddressed; } -int i2c_byte_write(i2c_t *obj, int data) +static int i2c_slave_write(i2c_t *obj, const void *data, uint32_t length) { - int ret_value = 1; - uint8_t statusFlags = 0; - I2C_Type *base = i2c_addrs[obj->instance]; + I2C_Type *base = i2c_addrs[obj->instance]; - /* Setup the I2C peripheral to transmit data. */ - base->C1 |= I2C_C1_TX_MASK; + I2C_SlaveWriteBlocking(base, (uint8_t *)data, length); - /* Send a byte of data. */ - base->D = data; + /* Switch to receive mode. */ + base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); + /* Read dummy to release bus. */ + base->D; - /* Wait until data transfer complete. */ - while (!(base->S & kI2C_IntPendingFlag)) { - } - - statusFlags = base->S; + return length; +} - /* Clear the IICIF flag. */ - base->S = kI2C_IntPendingFlag; +void i2c_slave_address(i2c_t *obj, uint16_t address) +{ + if (!obj->is_slave) { + return; + } - /* Check if arbitration lost */ - if (statusFlags & kI2C_ArbitrationLostFlag) { - base->S = kI2C_ArbitrationLostFlag; - ret_value = 2; - } + i2c_addrs[obj->instance]->A1 = (address & 0xFEU); +} +#endif // DEVICE_I2CSLAVE - /* Check if no acknowledgement (NAK) */ - if (statusFlags & kI2C_ReceiveNakFlag) { - base->S = kI2C_ReceiveNakFlag; - ret_value = 0; - } +int32_t i2c_read(i2c_t *obj, uint16_t address, void *data, uint32_t length, + bool last) +{ + if ((length == 0) || (data == NULL)) { + return 0; + } - return ret_value; +#if DEVICE_I2CSLAVE + /* Slave block read */ + if (obj->is_slave) { + return i2c_slave_read(obj, data, length); + } +#endif // DEVICE_I2CSLAVE + + /* Master block read */ + return i2c_block_read(obj, address, data, length, last); } const PinMap *i2c_master_sda_pinmap() @@ -264,73 +271,71 @@ const PinMap *i2c_slave_scl_pinmap() return PinMap_I2C_SCL; } - -#if DEVICE_I2CSLAVE -void i2c_slave_mode(i2c_t *obj, int enable_slave) +int i2c_block_write(i2c_t *obj, uint16_t address, const void *data, uint32_t length, bool stop) { - i2c_slave_config_t slave_config; - I2C_SlaveGetDefaultConfig(&slave_config); - slave_config.slaveAddress = 0; - slave_config.enableSlave = (bool)enable_slave; -#if FSL_I2C_DRIVER_VERSION > MAKE_VERSION(2, 0, 1) - I2C_SlaveInit(i2c_addrs[obj->instance], &slave_config, CLOCK_GetFreq(i2c_clocks[obj->instance])); -#else - I2C_SlaveInit(i2c_addrs[obj->instance], &slave_config); -#endif -} + I2C_Type *base = i2c_addrs[obj->instance]; -int i2c_slave_receive(i2c_t *obj) -{ - uint32_t status_flags = I2C_SlaveGetStatusFlags(i2c_addrs[obj->instance]); - - if (status_flags & kI2C_AddressMatchFlag) { - if (status_flags & kI2C_TransferDirectionFlag) { - // read addressed - return 1; - } else { - // write addressed - return 3; - } - } else { - // slave not addressed - return 0; + i2c_master_transfer_t master_xfer; + + if (length == 0) { + if (I2C_MasterStart(base, address >> 1, kI2C_Write) != kStatus_Success) { + return I2C_ERROR_NO_SLAVE; } -} -int i2c_slave_read(i2c_t *obj, char *data, int length) -{ - I2C_Type *base = i2c_addrs[obj->instance]; + while (!(base->S & kI2C_IntPendingFlag)) { + } - if (base->S & kI2C_AddressMatchFlag) { - /* Slave receive, master writing to slave. */ - base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); - /* Read dummy to release the bus. */ - base->D; + base->S = kI2C_IntPendingFlag; + + if (base->S & kI2C_ReceiveNakFlag) { + i2c_stop(obj); + return I2C_ERROR_NO_SLAVE; + } else { + i2c_stop(obj); + return length; } + } - I2C_SlaveReadBlocking(base, (uint8_t *)data, length); + memset(&master_xfer, 0, sizeof(master_xfer)); + master_xfer.slaveAddress = address >> 1; + master_xfer.direction = kI2C_Write; + master_xfer.data = (uint8_t *)data; + master_xfer.dataSize = length; - return length; -} + if (obj->next_repeated_start) { + master_xfer.flags |= kI2C_TransferRepeatedStartFlag; + } -int i2c_slave_write(i2c_t *obj, const char *data, int length) -{ - I2C_Type *base = i2c_addrs[obj->instance]; + if (!stop) { + master_xfer.flags |= kI2C_TransferNoStopFlag; + } - I2C_SlaveWriteBlocking(base, (uint8_t *)data, length); + obj->next_repeated_start = + master_xfer.flags & kI2C_TransferNoStopFlag ? 1 : 0; - /* Switch to receive mode. */ - base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK); - /* Read dummy to release bus. */ - base->D; + if (I2C_MasterTransferBlocking(base, &master_xfer) != kStatus_Success) { + return I2C_ERROR_NO_SLAVE; + } - return length; + return length; } -void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) +int32_t i2c_write(i2c_t *obj, uint16_t address, const void *data, + uint32_t length, bool stop) { - i2c_addrs[obj->instance]->A1 = address & 0xfe; + if ((length == 0) || (data == NULL)) { + return 0; + } + +#if DEVICE_I2CSLAVE + /* Slave block write */ + if (obj->is_slave) { + return i2c_slave_write(obj, data, length); + } +#endif // DEVICE_I2CSLAVE + + /* Master block write */ + return i2c_block_write(obj, address, data, length, stop); } -#endif -#endif +#endif // DEVICE_I2C diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/objects.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/objects.h index 405f2e17785..3200a5dca56 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/objects.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/objects.h @@ -68,6 +68,7 @@ struct analogin_s { struct i2c_s { uint32_t instance; uint8_t next_repeated_start; + bool is_slave; }; struct spi_s { diff --git a/targets/TARGET_STM/TARGET_STM32F0/common_objects.h b/targets/TARGET_STM/TARGET_STM32F0/common_objects.h index 1491acc4a82..30f55d48867 100644 --- a/targets/TARGET_STM/TARGET_STM32F0/common_objects.h +++ b/targets/TARGET_STM/TARGET_STM32F0/common_objects.h @@ -97,6 +97,7 @@ struct i2c_s { IRQn_Type event_i2cIRQ; IRQn_Type error_i2cIRQ; uint32_t XferOperation; + uint32_t clock_stretching_enabled; volatile uint8_t event; volatile int pending_start; #if DEVICE_I2CSLAVE @@ -108,6 +109,7 @@ struct i2c_s { uint32_t address; uint8_t stop; uint8_t available_events; + uint8_t tx_complete; #endif }; diff --git a/targets/TARGET_STM/TARGET_STM32F1/common_objects.h b/targets/TARGET_STM/TARGET_STM32F1/common_objects.h index 827aa644ded..853bea772ab 100644 --- a/targets/TARGET_STM/TARGET_STM32F1/common_objects.h +++ b/targets/TARGET_STM/TARGET_STM32F1/common_objects.h @@ -97,6 +97,7 @@ struct i2c_s { IRQn_Type event_i2cIRQ; IRQn_Type error_i2cIRQ; uint32_t XferOperation; + uint32_t clock_stretching_enabled; volatile uint8_t event; #if DEVICE_I2CSLAVE uint8_t slave; @@ -107,6 +108,7 @@ struct i2c_s { uint32_t address; uint8_t stop; uint8_t available_events; + uint8_t tx_complete; #endif }; diff --git a/targets/TARGET_STM/TARGET_STM32F2/objects.h b/targets/TARGET_STM/TARGET_STM32F2/objects.h index b463dea41ac..64771d636db 100644 --- a/targets/TARGET_STM/TARGET_STM32F2/objects.h +++ b/targets/TARGET_STM/TARGET_STM32F2/objects.h @@ -114,6 +114,7 @@ struct i2c_s { IRQn_Type event_i2cIRQ; IRQn_Type error_i2cIRQ; uint8_t XferOperation; + uint32_t clock_stretching_enabled; volatile uint8_t event; #if DEVICE_I2CSLAVE uint8_t slave; @@ -124,6 +125,7 @@ struct i2c_s { uint32_t address; uint8_t stop; uint8_t available_events; + uint8_t tx_complete; #endif }; diff --git a/targets/TARGET_STM/TARGET_STM32F3/common_objects.h b/targets/TARGET_STM/TARGET_STM32F3/common_objects.h index c2a227901b7..f941cc50462 100644 --- a/targets/TARGET_STM/TARGET_STM32F3/common_objects.h +++ b/targets/TARGET_STM/TARGET_STM32F3/common_objects.h @@ -97,6 +97,7 @@ struct i2c_s { IRQn_Type event_i2cIRQ; IRQn_Type error_i2cIRQ; uint32_t XferOperation; + uint32_t clock_stretching_enabled; volatile uint8_t event; volatile int pending_start; #if DEVICE_I2CSLAVE @@ -108,6 +109,7 @@ struct i2c_s { uint32_t address; uint8_t stop; uint8_t available_events; + uint8_t tx_complete; #endif }; diff --git a/targets/TARGET_STM/TARGET_STM32F4/common_objects.h b/targets/TARGET_STM/TARGET_STM32F4/common_objects.h index f4a7ef74f4c..e65314311ac 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/common_objects.h +++ b/targets/TARGET_STM/TARGET_STM32F4/common_objects.h @@ -97,6 +97,7 @@ struct i2c_s { IRQn_Type event_i2cIRQ; IRQn_Type error_i2cIRQ; uint8_t XferOperation; + uint32_t clock_stretching_enabled; volatile uint8_t event; #if DEVICE_I2CSLAVE uint8_t slave; @@ -107,6 +108,7 @@ struct i2c_s { uint32_t address; uint8_t stop; uint8_t available_events; + uint8_t tx_complete; #endif }; diff --git a/targets/TARGET_STM/TARGET_STM32F7/common_objects.h b/targets/TARGET_STM/TARGET_STM32F7/common_objects.h index a59d41630b8..d1fbcc2fff7 100644 --- a/targets/TARGET_STM/TARGET_STM32F7/common_objects.h +++ b/targets/TARGET_STM/TARGET_STM32F7/common_objects.h @@ -97,6 +97,7 @@ struct i2c_s { IRQn_Type event_i2cIRQ; IRQn_Type error_i2cIRQ; uint32_t XferOperation; + uint32_t clock_stretching_enabled; volatile uint8_t event; volatile int pending_start; #if DEVICE_I2CSLAVE @@ -108,6 +109,7 @@ struct i2c_s { uint32_t address; uint8_t stop; uint8_t available_events; + uint8_t tx_complete; #endif }; diff --git a/targets/TARGET_STM/TARGET_STM32L0/common_objects.h b/targets/TARGET_STM/TARGET_STM32L0/common_objects.h index 5f0acc6132e..6f84f98ab0b 100644 --- a/targets/TARGET_STM/TARGET_STM32L0/common_objects.h +++ b/targets/TARGET_STM/TARGET_STM32L0/common_objects.h @@ -97,6 +97,7 @@ struct i2c_s { IRQn_Type event_i2cIRQ; IRQn_Type error_i2cIRQ; uint32_t XferOperation; + uint32_t clock_stretching_enabled; volatile uint8_t event; volatile int pending_start; #if DEVICE_I2CSLAVE @@ -108,6 +109,7 @@ struct i2c_s { uint32_t address; uint8_t stop; uint8_t available_events; + uint8_t tx_complete; #endif }; diff --git a/targets/TARGET_STM/TARGET_STM32L1/common_objects.h b/targets/TARGET_STM/TARGET_STM32L1/common_objects.h index e25271a44d8..6256cab5139 100644 --- a/targets/TARGET_STM/TARGET_STM32L1/common_objects.h +++ b/targets/TARGET_STM/TARGET_STM32L1/common_objects.h @@ -97,6 +97,7 @@ struct i2c_s { IRQn_Type event_i2cIRQ; IRQn_Type error_i2cIRQ; uint32_t XferOperation; + uint32_t clock_stretching_enabled; volatile uint8_t event; #if DEVICE_I2CSLAVE uint8_t slave; @@ -107,6 +108,7 @@ struct i2c_s { uint32_t address; uint8_t stop; uint8_t available_events; + uint8_t tx_complete; #endif }; diff --git a/targets/TARGET_STM/TARGET_STM32L4/common_objects.h b/targets/TARGET_STM/TARGET_STM32L4/common_objects.h index 8f1beef3ad1..6309c535c22 100644 --- a/targets/TARGET_STM/TARGET_STM32L4/common_objects.h +++ b/targets/TARGET_STM/TARGET_STM32L4/common_objects.h @@ -97,6 +97,7 @@ struct i2c_s { IRQn_Type event_i2cIRQ; IRQn_Type error_i2cIRQ; uint32_t XferOperation; + uint32_t clock_stretching_enabled; volatile uint8_t event; volatile int pending_start; #if DEVICE_I2CSLAVE @@ -108,6 +109,7 @@ struct i2c_s { uint32_t address; uint8_t stop; uint8_t available_events; + uint8_t tx_complete; #endif }; diff --git a/targets/TARGET_STM/i2c_api.c b/targets/TARGET_STM/i2c_api.c index 121981e11e0..25c659e2c2b 100644 --- a/targets/TARGET_STM/i2c_api.c +++ b/targets/TARGET_STM/i2c_api.c @@ -40,6 +40,10 @@ #include "PeripheralPins.h" #include "i2c_device.h" // family specific defines +#ifdef I2C_IP_VERSION_V2 +#include +#endif // I2C_IP_VERSION_V2 + #ifndef DEBUG_STDIO # define DEBUG_STDIO 0 #endif @@ -79,8 +83,8 @@ static I2C_HandleTypeDef *i2c_handles[I2C_NUM]; */ #define FLAG_TIMEOUT ((int)0x1000) -/* Declare i2c_init_internal to be used in this file */ -void i2c_init_internal(i2c_t *obj, PinName sda, PinName scl); +#define MINIMUM_FREQUENCY 100000 +#define MAXIMUM_FREQUENCY 1000000 /* GENERIC INIT and HELPERS FUNCTIONS */ @@ -261,14 +265,74 @@ void i2c_sw_reset(i2c_t *obj) handle->Instance->CR1 |= I2C_CR1_PE; } -void i2c_init(i2c_t *obj, PinName sda, PinName scl) +#ifdef DEVICE_I2CSLAVE + +static int i2c_slave_read(i2c_t *obj, char *data, int length) +{ + struct i2c_s *obj_s = I2C_S(obj); + I2C_HandleTypeDef *handle = &(obj_s->handle); + int ret = 0; + uint32_t timeout = 0; + + /* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */ + ret = HAL_I2C_Slave_Sequential_Receive_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME); + + if (ret == HAL_OK) { + timeout = BYTE_TIMEOUT_US * (length + 1); + while (obj_s->pending_slave_rx_maxter_tx && (--timeout != 0)) { + wait_us(1); + } + + if (timeout == 0) { + DEBUG_PRINTF("TIMEOUT or error in i2c_slave_read\r\n"); + } + } + + return (length - handle->XferCount); +} + +static int i2c_slave_write(i2c_t *obj, const char *data, int length) +{ + struct i2c_s *obj_s = I2C_S(obj); + I2C_HandleTypeDef *handle = &(obj_s->handle); + int ret = 0; + uint32_t timeout = 0; + + /* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */ + ret = HAL_I2C_Slave_Sequential_Transmit_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME); + + if (ret == HAL_OK) { + timeout = BYTE_TIMEOUT_US * (length + 1); + while (obj_s->pending_slave_tx_master_rx && (--timeout != 0)) { + wait_us(1); + } + + if (timeout == 0) { + DEBUG_PRINTF("TIMEOUT or error in i2c_slave_write\r\n"); + } + } + + return (length - handle->XferCount); +} + +#endif + +void i2c_get_capabilities(i2c_capabilities_t *capabilities) { - memset(obj, 0, sizeof(*obj)); - i2c_init_internal(obj, sda, scl); + if (capabilities == NULL) { + return; + } + + capabilities->minimum_frequency = MINIMUM_FREQUENCY; + capabilities->maximum_frequency = MAXIMUM_FREQUENCY; + capabilities->supports_slave_mode = true; + capabilities->supports_10bit_addressing = false; + capabilities->supports_multi_master = true; } -void i2c_init_internal(i2c_t *obj, PinName sda, PinName scl) +void i2c_init(i2c_t *obj, PinName sda, PinName scl, bool is_slave) { + struct i2c_s *obj_s = I2C_S(obj); // Determine the I2C to use @@ -345,22 +409,45 @@ void i2c_init_internal(i2c_t *obj, PinName sda, PinName scl) #if DEVICE_I2CSLAVE // I2C master by default - obj_s->slave = 0; + obj_s->slave = (is_slave ? 1 : 0); obj_s->pending_slave_tx_master_rx = 0; obj_s->pending_slave_rx_maxter_tx = 0; #endif +#if DEVICE_I2C_ASYNCH + obj_s->tx_complete = 0; +#endif // DEVICE_I2C_ASYNCH + // I2C Xfer operation init obj_s->event = 0; obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME; + obj_s->clock_stretching_enabled = I2C_NOSTRETCH_DISABLE; #ifdef I2C_IP_VERSION_V2 obj_s->pending_start = 0; #endif + + I2C_HandleTypeDef *handle = &(obj_s->handle); + + if (is_slave) { + HAL_I2C_EnableListen_IT(handle); + } else { + HAL_I2C_DisableListen_IT(handle); + } } -void i2c_frequency(i2c_t *obj, int hz) +void i2c_free(i2c_t *obj) +{ + struct i2c_s *obj_s = I2C_S(obj); + + I2C_HandleTypeDef *handle = &(obj_s->handle); + + HAL_I2C_DeInit(handle); +} + +uint32_t i2c_frequency(i2c_t *obj, uint32_t frequency) { int timeout; + uint32_t selected_frequency = frequency; struct i2c_s *obj_s = I2C_S(obj); I2C_HandleTypeDef *handle = &(obj_s->handle); @@ -369,16 +456,29 @@ void i2c_frequency(i2c_t *obj, int hz) while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (--timeout != 0)); #ifdef I2C_IP_VERSION_V1 - handle->Init.ClockSpeed = hz; + handle->Init.ClockSpeed = selected_frequency; handle->Init.DutyCycle = I2C_DUTYCYCLE_2; #endif #ifdef I2C_IP_VERSION_V2 - /* Only predefined timing for below frequencies are supported */ - MBED_ASSERT((hz == 100000) || (hz == 400000) || (hz == 1000000)); - handle->Init.Timing = get_i2c_timing(hz); + // Find the closest supported frequency + static const int supported_hz[] = {100000, 400000, 1000000}; + uint32_t minimum_delta = -1; + + for (size_t i = 0; i < (sizeof(supported_hz) / sizeof(int)); ++i) + { + const uint32_t current_delta = abs(supported_hz[i] - frequency); + + if (current_delta < minimum_delta) + continue; + + selected_frequency = supported_hz[i]; + minimum_delta = current_delta; + } + + handle->Init.Timing = get_i2c_timing(selected_frequency); // Enable the Fast Mode Plus capability - if (hz == 1000000) { + if (selected_frequency == 1000000) { #if defined(I2C1_BASE) && defined(__HAL_SYSCFG_FASTMODEPLUS_ENABLE) && defined (I2C_FASTMODEPLUS_I2C1) if (obj_s->i2c == I2C_1) { HAL_I2CEx_EnableFastModePlus(I2C_FASTMODEPLUS_I2C1); @@ -433,15 +533,39 @@ void i2c_frequency(i2c_t *obj, int hz) handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; - handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + handle->Init.NoStretchMode = obj_s->clock_stretching_enabled; handle->Init.OwnAddress1 = 0; handle->Init.OwnAddress2 = 0; HAL_I2C_Init(handle); /* store frequency for timeout computation */ - obj_s->hz = hz; + obj_s->hz = selected_frequency; + + return obj_s->hz; +} + +void i2c_set_clock_stretching(i2c_t *obj, const bool enabled) +{ + struct i2c_s *obj_s = I2C_S(obj); + I2C_HandleTypeDef *handle = &(obj_s->handle); + + obj_s->clock_stretching_enabled = + enabled ? I2C_NOSTRETCH_DISABLE : I2C_NOSTRETCH_ENABLE; + + // wait before init + int wait = BYTE_TIMEOUT; + while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (--wait != 0)); + + // I2C configuration + handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + handle->Init.NoStretchMode = obj_s->clock_stretching_enabled; + + HAL_I2C_Init(handle); } + i2c_t *get_i2c_obj(I2C_HandleTypeDef *hi2c) { /* Aim of the function is to get i2c_s pointer using hi2c pointer */ @@ -456,24 +580,14 @@ i2c_t *get_i2c_obj(I2C_HandleTypeDef *hi2c) return (obj); } -void i2c_reset(i2c_t *obj) -{ - struct i2c_s *obj_s = I2C_S(obj); - /* As recommended in i2c_api.h, mainly send stop */ - i2c_stop(obj); - /* then re-init */ - i2c_init_internal(obj, obj_s->sda, obj_s->scl); -} - /* * UNITARY APIS. * For very basic operations, direct registers access is needed * There are 2 different IPs version that need to be supported */ #ifdef I2C_IP_VERSION_V1 -int i2c_start(i2c_t *obj) +void i2c_start(i2c_t *obj) { - int timeout; struct i2c_s *obj_s = I2C_S(obj); I2C_HandleTypeDef *handle = &(obj_s->handle); @@ -486,7 +600,7 @@ int i2c_start(i2c_t *obj) timeout = FLAG_TIMEOUT; while ((handle->Instance->CR1 & I2C_CR1_STOP) == I2C_CR1_STOP) { if ((timeout--) == 0) { - return 1; + return; } } @@ -497,14 +611,12 @@ int i2c_start(i2c_t *obj) timeout = FLAG_TIMEOUT; while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) { if ((timeout--) == 0) { - return 1; + return; } } - - return 0; } -int i2c_stop(i2c_t *obj) +void i2c_stop(i2c_t *obj) { struct i2c_s *obj_s = I2C_S(obj); I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c; @@ -516,10 +628,15 @@ int i2c_stop(i2c_t *obj) * re-init HAL state */ if (obj_s->XferOperation != I2C_FIRST_AND_LAST_FRAME) { - i2c_init_internal(obj, obj_s->sda, obj_s->scl); - } - return 0; +#ifdef DEVICE_I2CSLAVE + const bool is_slave = obj_s->slave ? true : false; +#else + const bool is_slave = false; +#endif + + i2c_init(obj, obj_s->sda, obj_s->scl, is_slave); + } } int i2c_byte_read(i2c_t *obj, int last) @@ -576,15 +693,14 @@ int i2c_byte_write(i2c_t *obj, int data) #endif //I2C_IP_VERSION_V1 #ifdef I2C_IP_VERSION_V2 -int i2c_start(i2c_t *obj) +void i2c_start(i2c_t *obj) { struct i2c_s *obj_s = I2C_S(obj); /* This I2C IP doesn't */ obj_s->pending_start = 1; - return 0; } -int i2c_stop(i2c_t *obj) +void i2c_stop(i2c_t *obj) { struct i2c_s *obj_s = I2C_S(obj); I2C_HandleTypeDef *handle = &(obj_s->handle); @@ -592,8 +708,8 @@ int i2c_stop(i2c_t *obj) #if DEVICE_I2CSLAVE if (obj_s->slave) { /* re-init slave when stop is requested */ - i2c_init_internal(obj, obj_s->sda, obj_s->scl); - return 0; + i2c_init(obj, obj_s->sda, obj_s->scl, true); + return; } #endif // Disable reload mode @@ -604,7 +720,7 @@ int i2c_stop(i2c_t *obj) timeout = FLAG_TIMEOUT; while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXIS)) { if ((timeout--) == 0) { - return I2C_ERROR_BUS_BUSY; + return; } } } @@ -615,7 +731,7 @@ int i2c_stop(i2c_t *obj) timeout = FLAG_TIMEOUT; while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_STOPF)) { if ((timeout--) == 0) { - return I2C_ERROR_BUS_BUSY; + return; } } @@ -635,10 +751,8 @@ int i2c_stop(i2c_t *obj) /* In case of mixed usage of the APIs (unitary + SYNC) * re-init HAL state */ if (obj_s->XferOperation != I2C_FIRST_AND_LAST_FRAME) { - i2c_init_internal(obj, obj_s->sda, obj_s->scl); + i2c_init(obj, obj_s->sda, obj_s->scl, false); } - - return 0; } int i2c_byte_read(i2c_t *obj, int last) @@ -753,25 +867,29 @@ int i2c_byte_write(i2c_t *obj, int data) /* * SYNC APIS */ -int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) +int32_t i2c_read(i2c_t *obj, uint16_t address, void *data, uint32_t length, bool last) { struct i2c_s *obj_s = I2C_S(obj); I2C_HandleTypeDef *handle = &(obj_s->handle); - int count = I2C_ERROR_BUS_BUSY, ret = 0; - uint32_t timeout = 0; + +#ifdef DEVICE_I2CSLAVE + if (obj_s->slave == 1) { + return i2c_slave_read(obj, data, length); + } +#endif // Trick to remove compiler warning "left and right operands are identical" in some cases uint32_t op1 = I2C_FIRST_AND_LAST_FRAME; uint32_t op2 = I2C_LAST_FRAME; if ((obj_s->XferOperation == op1) || (obj_s->XferOperation == op2)) { - if (stop) { + if (last) { obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME; } else { obj_s->XferOperation = I2C_FIRST_FRAME; } } else if ((obj_s->XferOperation == I2C_FIRST_FRAME) || (obj_s->XferOperation == I2C_NEXT_FRAME)) { - if (stop) { + if (last) { obj_s->XferOperation = I2C_LAST_FRAME; } else { obj_s->XferOperation = I2C_NEXT_FRAME; @@ -785,37 +903,50 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) */ i2c_ev_err_enable(obj, i2c_get_irq_handler(obj)); - ret = HAL_I2C_Master_Sequential_Receive_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation); + const HAL_StatusTypeDef status = HAL_I2C_Master_Sequential_Receive_IT( + handle, address, (uint8_t *)data, length, obj_s->XferOperation); - if (ret == HAL_OK) { - timeout = BYTE_TIMEOUT_US * (length + 1); - /* transfer started : wait completion or timeout */ - while (!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) { - wait_us(1); - } + if (status != HAL_OK) { + DEBUG_PRINTF("ERROR in i2c_read:%d\r\n", status); - i2c_ev_err_disable(obj); + return I2C_ERROR_BUS_BUSY; + } - if ((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) { - DEBUG_PRINTF(" TIMEOUT or error in i2c_read\r\n"); - /* re-init IP to try and get back in a working state */ - i2c_init_internal(obj, obj_s->sda, obj_s->scl); - } else { - count = length; - } - } else { - DEBUG_PRINTF("ERROR in i2c_read:%d\r\n", ret); + uint32_t timeout = (BYTE_TIMEOUT_US * (length + 1)); + + /* transfer started : wait completion or timeout */ + while (!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) { + wait_us(1); } - return count; + i2c_ev_err_disable(obj); + + if ((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) { + DEBUG_PRINTF(" TIMEOUT or error in i2c_read\r\n"); + +#ifdef DEVICE_I2CSLAVE + i2c_init(obj, obj_s->sda, obj_s->scl, obj_s->slave); +#else + i2c_init(obj, obj_s->sda, obj_s->scl, false); +#endif // DEVICE_I2CSLAVE + + + return I2C_ERROR_TIMEOUT; + } + + return (length - handle->XferCount); } -int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) +int32_t i2c_write(i2c_t *obj, uint16_t address, const void *data, uint32_t length, bool stop) { struct i2c_s *obj_s = I2C_S(obj); I2C_HandleTypeDef *handle = &(obj_s->handle); - int count = I2C_ERROR_BUS_BUSY, ret = 0; - uint32_t timeout = 0; + +#ifdef DEVICE_I2CSLAVE + if (obj_s->slave == 1) { + return i2c_slave_write(obj, data, length); + } +#endif // Trick to remove compiler warning "left and right operands are identical" in some cases uint32_t op1 = I2C_FIRST_AND_LAST_FRAME; @@ -839,29 +970,37 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) i2c_ev_err_enable(obj, i2c_get_irq_handler(obj)); - ret = HAL_I2C_Master_Sequential_Transmit_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation); + const HAL_StatusTypeDef status = HAL_I2C_Master_Sequential_Transmit_IT( + handle, address, (uint8_t *)data, length, obj_s->XferOperation); - if (ret == HAL_OK) { - timeout = BYTE_TIMEOUT_US * (length + 1); - /* transfer started : wait completion or timeout */ - while (!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) { - wait_us(1); - } + if (status != HAL_OK) { + DEBUG_PRINTF("ERROR in i2c_write\r\n"); - i2c_ev_err_disable(obj); + return I2C_ERROR_BUS_BUSY; + } - if ((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) { - DEBUG_PRINTF(" TIMEOUT or error in i2c_write\r\n"); - /* re-init IP to try and get back in a working state */ - i2c_init_internal(obj, obj_s->sda, obj_s->scl); - } else { - count = length; - } - } else { - DEBUG_PRINTF("ERROR in i2c_read\r\n"); + uint32_t timeout = (BYTE_TIMEOUT_US * (length + 1)); + + /* transfer started : wait completion or timeout */ + while (!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) { + wait_us(1); } - return count; + i2c_ev_err_disable(obj); + + if ((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) { + DEBUG_PRINTF(" TIMEOUT or error in i2c_write\r\n"); + +#ifdef DEVICE_I2CSLAVE + i2c_init(obj, obj_s->sda, obj_s->scl, obj_s->slave); +#else + i2c_init(obj, obj_s->sda, obj_s->scl, false); +#endif // DEVICE_I2CSLAVE + + return I2C_ERROR_TIMEOUT; + } + + return (length - handle->XferCount); } void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) @@ -869,6 +1008,9 @@ void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) /* Get object ptr based on handler ptr */ i2c_t *obj = get_i2c_obj(hi2c); struct i2c_s *obj_s = I2C_S(obj); + I2C_HandleTypeDef *handle = &(obj_s->handle); + + obj_s->tx_complete = 1; #if DEVICE_I2C_ASYNCH /* Handle potential Tx/Rx use case */ @@ -885,6 +1027,23 @@ void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) { /* Set event flag */ obj_s->event = I2C_EVENT_TRANSFER_COMPLETE; + +#if DEVICE_I2C_ASYNCH + /* */ + if (obj->handler == NULL) { + return; + } + + i2c_async_event_t event; + event.sent_bytes = (obj->tx_buff.length - handle->XferCount); + event.received_bytes = 0; + event.error = false; + + obj->handler(obj, &event, obj->ctx); + + obj->handler = NULL; + obj->ctx = NULL; +#endif // DEVICE_I2C_ASYNCH } } @@ -893,9 +1052,27 @@ void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) /* Get object ptr based on handler ptr */ i2c_t *obj = get_i2c_obj(hi2c); struct i2c_s *obj_s = I2C_S(obj); + I2C_HandleTypeDef *handle = &(obj_s->handle); /* Set event flag */ obj_s->event = I2C_EVENT_TRANSFER_COMPLETE; + +#if DEVICE_I2C_ASYNCH + /* */ + if (obj->handler == NULL) { + return; + } + + i2c_async_event_t event; + event.sent_bytes = obj->tx_buff.length; + event.received_bytes = (obj->rx_buff.length - handle->XferCount); + event.error = false; + + obj->handler(obj, &event, obj->ctx); + + obj->handler = NULL; + obj->ctx = NULL; +#endif // DEVICE_I2C_ASYNCH } void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) @@ -905,7 +1082,7 @@ void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) struct i2c_s *obj_s = I2C_S(obj); #if DEVICE_I2CSLAVE I2C_HandleTypeDef *handle = &(obj_s->handle); - uint32_t address = 0; + uint16_t address = 0; /* Store address to handle it after reset */ if (obj_s->slave) { address = handle->Init.OwnAddress1; @@ -915,18 +1092,46 @@ void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) DEBUG_PRINTF("HAL_I2C_ErrorCallback:%d, index=%d\r\n", (int) hi2c->ErrorCode, obj_s->index); /* re-init IP to try and get back in a working state */ - i2c_init_internal(obj, obj_s->sda, obj_s->scl); +#ifdef DEVICE_I2CSLAVE + const bool is_slave = obj_s->slave ? true : false; +#else + const bool is_slave = false; +#endif + i2c_init(obj, obj_s->sda, obj_s->scl, is_slave); #if DEVICE_I2CSLAVE /* restore slave address */ if (address != 0) { obj_s->slave = 1; - i2c_slave_address(obj, 0, address, 0); + i2c_slave_address(obj, address); } #endif /* Keep Set event flag */ obj_s->event = I2C_EVENT_ERROR; + +#if DEVICE_I2C_ASYNCH + /* */ + if (obj->handler == NULL) { + return; + } + + i2c_async_event_t event; + event.error = true; + + if (!obj_s->tx_complete) { + event.sent_bytes = (obj->tx_buff.length - handle->XferCount); + event.received_bytes = 0; + } else { + event.sent_bytes = (obj->tx_buff.length); + event.received_bytes = (obj->rx_buff.length - handle->XferCount); + } + + obj->handler(obj, &event, obj->ctx); + + obj->handler = NULL; + obj->ctx = NULL; +#endif // DEVICE_I2C_ASYNCH } const PinMap *i2c_master_sda_pinmap() @@ -951,13 +1156,13 @@ const PinMap *i2c_slave_scl_pinmap() #if DEVICE_I2CSLAVE /* SLAVE API FUNCTIONS */ -void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) +void i2c_slave_address(i2c_t *obj, uint16_t address) { struct i2c_s *obj_s = I2C_S(obj); I2C_HandleTypeDef *handle = &(obj_s->handle); // I2C configuration - handle->Init.OwnAddress1 = address; + handle->Init.OwnAddress1 = address; HAL_I2C_Init(handle); i2c_ev_err_enable(obj, i2c_get_irq_handler(obj)); @@ -965,28 +1170,6 @@ void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) HAL_I2C_EnableListen_IT(handle); } -void i2c_slave_mode(i2c_t *obj, int enable_slave) -{ - - struct i2c_s *obj_s = I2C_S(obj); - I2C_HandleTypeDef *handle = &(obj_s->handle); - - if (enable_slave) { - obj_s->slave = 1; - HAL_I2C_EnableListen_IT(handle); - } else { - obj_s->slave = 0; - HAL_I2C_DisableListen_IT(handle); - } -} - -// See I2CSlave.h -#define NoData 0 // the slave has not been addressed -#define ReadAddressed 1 // the master has requested a read from this slave (slave = transmitter) -#define WriteGeneral 2 // the master is writing to all slave -#define WriteAddressed 3 // the master is writing to this slave (slave = receiver) - - void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) { /* Get object ptr based on handler ptr */ @@ -1025,11 +1208,11 @@ void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) HAL_I2C_EnableListen_IT(hi2c); } -int i2c_slave_receive(i2c_t *obj) +i2c_slave_status_t i2c_slave_status(i2c_t *obj) { - struct i2c_s *obj_s = I2C_S(obj); - int retValue = NoData; + + i2c_slave_status_t retValue = NoData; if (obj_s->pending_slave_rx_maxter_tx) { retValue = WriteAddressed; @@ -1039,60 +1222,7 @@ int i2c_slave_receive(i2c_t *obj) retValue = ReadAddressed; } - return (retValue); -} - -int i2c_slave_read(i2c_t *obj, char *data, int length) -{ - struct i2c_s *obj_s = I2C_S(obj); - I2C_HandleTypeDef *handle = &(obj_s->handle); - int count = 0; - int ret = 0; - uint32_t timeout = 0; - - /* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */ - ret = HAL_I2C_Slave_Sequential_Receive_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME); - - if (ret == HAL_OK) { - timeout = BYTE_TIMEOUT_US * (length + 1); - while (obj_s->pending_slave_rx_maxter_tx && (--timeout != 0)) { - wait_us(1); - } - - if (timeout != 0) { - count = length; - } else { - DEBUG_PRINTF("TIMEOUT or error in i2c_slave_read\r\n"); - } - } - return count; -} - -int i2c_slave_write(i2c_t *obj, const char *data, int length) -{ - struct i2c_s *obj_s = I2C_S(obj); - I2C_HandleTypeDef *handle = &(obj_s->handle); - int count = 0; - int ret = 0; - uint32_t timeout = 0; - - /* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */ - ret = HAL_I2C_Slave_Sequential_Transmit_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME); - - if (ret == HAL_OK) { - timeout = BYTE_TIMEOUT_US * (length + 1); - while (obj_s->pending_slave_tx_master_rx && (--timeout != 0)) { - wait_us(1); - } - - if (timeout != 0) { - count = length; - } else { - DEBUG_PRINTF("TIMEOUT or error in i2c_slave_write\r\n"); - } - } - - return count; + return retValue; } #endif // DEVICE_I2CSLAVE @@ -1111,34 +1241,57 @@ void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c) /* Set event flag */ obj_s->event = I2C_EVENT_ERROR; -} -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) -{ + if (obj->handler == NULL) { + return; + } - // TODO: DMA usage is currently ignored by this way - (void) hint; +#if DEVICE_I2C_ASYNCH + i2c_async_event_t event; + event.error = true; + if (!obj_s->tx_complete) { + event.sent_bytes = (obj->tx_buff.length - handle->XferCount); + event.received_bytes = 0; + } else { + event.sent_bytes = (obj->tx_buff.length); + event.received_bytes = (obj->rx_buff.length - handle->XferCount); + } + + obj->handler(obj, &event, obj->ctx); + + obj->handler = NULL; + obj->ctx = NULL; +#endif // DEVICE_I2C_ASYNCH +} + +void i2c_transfer_async(i2c_t *obj, const void *tx, uint32_t tx_length, + void *rx, uint32_t rx_length, uint16_t address, + bool stop, i2c_async_handler_f handler, void *ctx) +{ struct i2c_s *obj_s = I2C_S(obj); I2C_HandleTypeDef *handle = &(obj_s->handle); /* Update object */ obj->tx_buff.buffer = (void *)tx; obj->tx_buff.length = tx_length; - obj->tx_buff.pos = 0; - obj->tx_buff.width = 8; + obj->tx_buff.pos = 0; + obj->tx_buff.width = 8; obj->rx_buff.buffer = (void *)rx; obj->rx_buff.length = rx_length; - obj->rx_buff.pos = SIZE_MAX; - obj->rx_buff.width = 8; + obj->rx_buff.pos = SIZE_MAX; + obj->rx_buff.width = 8; + + obj->handler = handler; + obj->ctx = ctx; - obj_s->available_events = event; obj_s->event = 0; obj_s->address = address; obj_s->stop = stop; + obj_s->tx_complete = 0; - i2c_ev_err_enable(obj, handler); + i2c_ev_err_enable(obj, i2c_get_irq_handler(obj)); /* Set operation step depending if stop sending required or not */ if ((tx_length && !rx_length) || (!tx_length && rx_length)) { @@ -1180,34 +1333,7 @@ void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, } } - -uint32_t i2c_irq_handler_asynch(i2c_t *obj) -{ - - struct i2c_s *obj_s = I2C_S(obj); - I2C_HandleTypeDef *handle = &(obj_s->handle); - - HAL_I2C_EV_IRQHandler(handle); - HAL_I2C_ER_IRQHandler(handle); - - /* Return I2C event status */ - return (obj_s->event & obj_s->available_events); -} - -uint8_t i2c_active(i2c_t *obj) -{ - - struct i2c_s *obj_s = I2C_S(obj); - I2C_HandleTypeDef *handle = &(obj_s->handle); - - if (handle->State == HAL_I2C_STATE_READY) { - return 0; - } else { - return 1; - } -} - -void i2c_abort_asynch(i2c_t *obj) +void i2c_abort_async(i2c_t *obj) { struct i2c_s *obj_s = I2C_S(obj); diff --git a/targets/targets.json b/targets/targets.json index 7126959e250..98e48119fdc 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -175,8 +175,6 @@ "device_has": [ "ANALOGIN", "CAN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -202,8 +200,6 @@ "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -232,8 +228,6 @@ "detect_code": ["1040"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", @@ -261,8 +255,6 @@ "extra_labels": ["NXP", "LPC11UXX"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -287,8 +279,6 @@ "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", @@ -316,8 +306,6 @@ "supported_toolchains": ["ARM", "uARM", "GCC_ARM"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -350,8 +338,6 @@ "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -378,8 +364,6 @@ "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -406,8 +390,6 @@ "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -436,8 +418,6 @@ "supported_toolchains": ["ARM", "uARM", "GCC_ARM", "IAR"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -468,8 +448,6 @@ "inherits": ["LPC11U37_501"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -495,8 +473,6 @@ "inherits": ["LPCTarget"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -521,8 +497,6 @@ "detect_code": ["1168"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", @@ -543,8 +517,6 @@ "supported_toolchains": ["ARM", "GCC_ARM", "IAR"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -571,7 +543,6 @@ "ANALOGIN", "ANALOGOUT", "CAN", - "I2C", "INTERRUPTIN", "PWMOUT", "SERIAL", @@ -598,8 +569,6 @@ "DEBUG_AWARENESS", "EMAC", "ETHERNET", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", @@ -648,8 +617,6 @@ "DEBUG_AWARENESS", "EMAC", "ETHERNET", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -699,8 +666,6 @@ "DEBUG_AWARENESS", "EMAC", "ETHERNET", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -735,8 +700,6 @@ "CAN", "DEBUG_AWARENESS", "ETHERNET", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", @@ -763,8 +726,6 @@ "is_disk_virtual": true, "supported_toolchains": ["uARM", "IAR", "GCC_ARM"], "device_has": [ - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", @@ -786,8 +747,6 @@ "inherits": ["LPCTarget"], "detect_code": ["1050"], "device_has": [ - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", @@ -810,8 +769,6 @@ "inherits": ["LPCTarget"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", @@ -832,8 +789,6 @@ "supported_toolchains": ["uARM", "GCC_ARM"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PWMOUT", "SERIAL", @@ -860,8 +815,6 @@ "DEBUG_AWARENESS", "EMAC", "ETHERNET", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -897,8 +850,6 @@ "ANALOGOUT", "DEBUG_AWARENESS", "ETHERNET", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -923,8 +874,6 @@ "ANALOGOUT", "DEBUG_AWARENESS", "ETHERNET", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -947,8 +896,6 @@ "ANALOGOUT", "DEBUG_AWARENESS", "ETHERNET", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -984,8 +931,6 @@ "inherits": ["LPCTarget"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1023,8 +968,6 @@ "USTICKER", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1053,8 +996,6 @@ "USTICKER", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1081,8 +1022,6 @@ "USTICKER", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1109,8 +1048,6 @@ "USTICKER", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1137,8 +1074,6 @@ "detect_code": ["0230"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1169,8 +1104,6 @@ "device_has": [ "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1210,8 +1143,6 @@ "RTC", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1248,8 +1179,6 @@ "LPTICKER", "RTC", "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTOUT", @@ -1279,8 +1208,6 @@ "RTC", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1312,8 +1239,6 @@ "RTC", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1352,8 +1277,6 @@ "LPTICKER", "RTC", "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1391,8 +1314,6 @@ "RTC", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1435,8 +1356,6 @@ "RTC", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1490,7 +1409,6 @@ "ANALOGOUT", "EMAC", "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1548,7 +1466,6 @@ "SLEEP", "INTERRUPTIN", "SPI", - "I2C", "ANALOGIN", "MPU" ], @@ -1579,7 +1496,6 @@ "SLEEP", "INTERRUPTIN", "SPI", - "I2C", "ANALOGIN", "MPU" ], @@ -1606,8 +1522,6 @@ "USTICKER", "LPTICKER", "RTC", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1643,8 +1557,6 @@ "RTC", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1696,8 +1608,6 @@ "LPTICKER", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1736,8 +1646,6 @@ "LPTICKER", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1778,8 +1686,6 @@ "ANALOGIN", "ANALOGOUT", "EMAC", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1817,8 +1723,6 @@ "RTC", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -1926,8 +1830,6 @@ "LPTICKER", "ANALOGIN", "EMAC", - "I2C", - "I2CSLAVE", "ERROR_RED", "INTERRUPTIN", "PORTIN", @@ -1965,8 +1867,6 @@ "USTICKER", "RTC", "ANALOGIN", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -2001,8 +1901,6 @@ "RTC", "ANALOGIN", "EMAC", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -4619,7 +4517,6 @@ "features": ["BLE"], "device_has": [ "ANALOGIN", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -4864,7 +4761,6 @@ "device_has": [ "ANALOGIN", "DEBUG_AWARENESS", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -4897,8 +4793,6 @@ "USTICKER", "LPTICKER", "ANALOGIN", - "I2C", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5012,8 +4906,6 @@ "USTICKER", "LPTICKER", "ANALOGIN", - "I2C", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5056,8 +4948,6 @@ "USTICKER", "LPTICKER", "ANALOGIN", - "I2C", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5093,7 +4983,6 @@ "ANALOGIN", "CLCD", "ETHERNET", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5120,7 +5009,6 @@ "ANALOGIN", "CLCD", "ETHERNET", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5144,7 +5032,6 @@ "ANALOGIN", "CLCD", "ETHERNET", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5168,7 +5055,6 @@ "ANALOGIN", "CLCD", "ETHERNET", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5192,7 +5078,6 @@ "ANALOGIN", "CLCD", "ETHERNET", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5216,7 +5101,6 @@ "ANALOGIN", "CLCD", "ETHERNET", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5237,7 +5121,6 @@ "ANALOGIN", "CLCD", "ETHERNET", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5260,7 +5143,6 @@ "ANALOGIN", "CLCD", "ETHERNET", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5285,7 +5167,6 @@ "ANALOGIN", "EMAC", "FLASH", - "I2C", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -5306,6 +5187,42 @@ "target.network-default-interface-type": "ETHERNET" } }, + "ARM_BEETLE_SOC": { + "inherits": ["ARM_IOTSS_Target"], + "core": "Cortex-M3", + "supported_toolchains": ["ARM", "GCC_ARM", "IAR"], + "default_toolchain": "ARM", + "extra_labels": ["ARM_SSG", "BEETLE"], + "macros": [ + "CMSDK_BEETLE", + "WSF_MS_PER_TICK=20", + "WSF_TOKEN_ENABLED=FALSE", + "WSF_TRACE_ENABLED=TRUE", + "WSF_ASSERT_ENABLED=FALSE", + "WSF_PRINTF_MAX_LEN=128", + "ASIC", + "CONFIG_HOST_REV=0x20", + "CONFIG_ALLOW_DEEP_SLEEP=FALSE", + "HCI_VS_TARGET", + "CONFIG_ALLOW_SETTING_WRITE=TRUE", + "WSF_MAX_HANDLERS=20", + "NO_LEDS" + ], + "device_has": [ + "ANALOGIN", + "CLCD", + "INTERRUPTIN", + "PORTIN", + "PORTINOUT", + "PORTOUT", + "SERIAL", + "SLEEP", + "SPI", + "MPU" + ], + "features": ["BLE"], + "release_versions": ["2", "5"] + }, "RZ_A1XX": { "inherits": ["Target"], "core": "Cortex-A9", @@ -5318,9 +5235,6 @@ "ANALOGIN", "CAN", "ETHERNET", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5379,7 +5293,6 @@ "device_has": [ "ANALOGIN", "ANALOGOUT", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5403,7 +5316,6 @@ "device_has": [ "ANALOGIN", "ANALOGOUT", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5424,7 +5336,6 @@ "supported_toolchains": ["GCC_ARM", "IAR", "ARM"], "device_has": [ "ANALOGIN", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -5454,7 +5365,6 @@ "device_has": [ "ANALOGIN", "FLASH", - "I2C", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -5485,7 +5395,6 @@ "device_has": [ "ANALOGIN", "FLASH", - "I2C", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -5509,7 +5418,6 @@ "supported_toolchains": ["GCC_ARM", "IAR", "ARM"], "device_has": [ "ANALOGIN", - "I2C", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -5559,7 +5467,6 @@ "supported_toolchains": ["GCC_ARM", "IAR", "ARM"], "device_has": [ "ANALOGIN", - "I2C", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -5603,9 +5510,6 @@ "device_has": [ "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -5680,9 +5584,6 @@ "device_has": [ "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -5758,9 +5659,6 @@ "device_has": [ "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -5834,9 +5732,6 @@ "inherits": ["EFM32ZG222F32"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -5907,9 +5802,6 @@ "inherits": ["EFM32HG322F64"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -5980,9 +5872,6 @@ "device_has": [ "ANALOGIN", "CRC", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -6079,9 +5968,6 @@ "802_15_4_PHY", "ANALOGIN", "CRC", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -6149,9 +6035,6 @@ "802_15_4_PHY", "ANALOGIN", "CRC", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -6226,9 +6109,6 @@ "device_has": [ "ANALOGIN", "CRC", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -6314,9 +6194,6 @@ "802_15_4_PHY", "ANALOGIN", "CRC", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -6394,9 +6271,6 @@ "ANALOGIN", "CRC", "EMAC", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "LPTICKER", "PORTIN", @@ -6476,7 +6350,6 @@ "inherits": ["Target"], "device_has": [ "ANALOGIN", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6501,7 +6374,6 @@ "inherits": ["Target"], "device_has": [ "ANALOGIN", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6525,7 +6397,6 @@ "supported_toolchains": ["uARM", "ARM", "GCC_ARM", "IAR"], "device_has": [ "ANALOGIN", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6552,9 +6423,6 @@ "supported_toolchains": ["GCC_ARM", "ARM", "uARM"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6586,9 +6454,6 @@ "device_has": [ "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6620,9 +6485,6 @@ "device_has": [ "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6654,9 +6516,6 @@ "device_has": [ "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6688,9 +6547,6 @@ "default_toolchain": "ARM", "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6767,7 +6623,6 @@ }, "device_has": [ "ANALOGIN", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6806,8 +6661,6 @@ "USTICKER", "LPTICKER", "ANALOGIN", - "I2C", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6830,8 +6683,6 @@ "USTICKER", "LPTICKER", "ANALOGIN", - "I2C", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6855,8 +6706,6 @@ "device_has": [ "USTICKER", "LPTICKER", - "I2C", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6878,8 +6727,6 @@ "USTICKER", "LPTICKER", "ANALOGIN", - "I2C", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -6908,8 +6755,6 @@ "device_has": [ "ANALOGIN", "FLASH", - "I2C", - "I2C_ASYNCH", "INTERRUPTIN", "ITM", "LPTICKER", @@ -7034,8 +6879,6 @@ "device_has": [ "ANALOGIN", "FLASH", - "I2C", - "I2C_ASYNCH", "INTERRUPTIN", "ITM", "LPTICKER", @@ -7157,9 +7000,6 @@ "LPTICKER", "RTC", "ANALOGIN", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -7231,7 +7071,6 @@ "device_has": [ "ANALOGIN", "SERIAL", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -7285,9 +7124,6 @@ "RTC", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -7354,9 +7190,6 @@ "RTC", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -7433,8 +7266,6 @@ "device_has": [ "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -7494,8 +7325,6 @@ "USTICKER", "LPTICKER", "ANALOGIN", - "I2C", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -7674,9 +7503,6 @@ "RTC", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -7733,8 +7559,6 @@ "PORTOUT", "SERIAL", "SLEEP", - "I2C", - "I2CSLAVE", "STDIO_MESSAGES", "PWMOUT" ], @@ -7749,9 +7573,6 @@ "extra_labels_add": ["STM32F4", "STM32F411xE", "STM32F411RE"], "device_has": [ "ANALOGIN", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -7797,7 +7618,6 @@ "SERIAL", "SERIAL_FC", "SPI", - "I2C", "STDIO_MESSAGES", "TRNG", "FLASH", @@ -7825,7 +7645,6 @@ "CLCD", "EMAC", "FLASH", - "I2C", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -7916,9 +7735,6 @@ "RTC", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2CSLAVE", - "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", @@ -7961,8 +7777,6 @@ "SERIAL", "SLEEP", "SPI", - "I2C", - "I2CSLAVE", "STDIO_MESSAGES", "MPU" ], @@ -7987,8 +7801,6 @@ "PWMOUT", "SERIAL", "SPI", - "I2C", - "I2CSLAVE", "STDIO_MESSAGES", "FLASH", "SLEEP", @@ -8020,8 +7832,6 @@ "PWMOUT", "ANALOGIN", "ANALOGOUT", - "I2C", - "I2C_ASYNCH", "SPI", "SPI_ASYNCH", "STDIO_MESSAGES", @@ -8318,8 +8128,6 @@ "SERIAL", "SLEEP", "SPI", - "I2C", - "I2CSLAVE", "STDIO_MESSAGES", "MPU" ], @@ -8382,9 +8190,7 @@ "extra_labels_add": ["GD32F30X", "GD32F307VG", "GD_EMAC"], "device_has_add": [ "RTC", - "I2C", "CAN", - "I2CSLAVE", "ANALOGOUT", "SPI", "SPISLAVE", @@ -8421,8 +8227,6 @@ "SERIAL", "SLEEP", "SPI", - "I2C", - "I2CSLAVE", "STDIO_MESSAGES", "MPU" ], @@ -8437,9 +8241,7 @@ "extra_labels_add": ["GD32F4XX", "GD32F450ZI", "GD_EMAC"], "device_has_add": [ "RTC", - "I2C", "CAN", - "I2CSLAVE", "ANALOGOUT", "SPI", "SPISLAVE", @@ -8466,9 +8268,7 @@ "extra_labels_add": ["GD32E10X", "GD32E103VB"], "device_has_add": [ "RTC", - "I2C", "CAN", - "I2CSLAVE", "ANALOGOUT", "SPI", "SPISLAVE",