PSOC E8XXGP Device Support Library

General Description

Driver API for EZI2C Slave Peripheral.

The functions and other declarations used in this part of the driver are in cy_scb_ezi2c.h. You can also include cy_pdl.h to get access to all functions and declarations in the PDL.

I2C - The Inter-Integrated Circuit (I2C) bus is an industry-standard.

The EZI2C slave peripheral driver provides an API to implement the I2C slave device based on the SCB hardware block. This slave device emulates a common I2C EEPROM interface that acts like dual-port memory between the external master and your code. I2C devices based on the SCB hardware are compatible with the I2C Standard mode, Fast mode, and Fast mode Plus specifications, as defined in the I2C bus specification.

EZI2C slave is a special implementation of the I2C that handles all communication between the master and slave through ISR (interrupt service routine) and requires no interaction with the main program flow from the slave side. The EZI2C should be used when a shared memory model between the I2C master and I2C slave is needed.

Features:

Configuration Considerations

The EZI2C slave driver configuration can be divided to number of sequential steps listed below:

Note
EZI2C slave driver is built on top of the SCB hardware block. The SCB3 instance is used as an example for all code snippets. Modify the code to match your design.

Configure EZI2C slave

To set up the EZI2C slave driver, provide the configuration parameters in the cy_stc_scb_ezi2c_config_t structure. The primary slave address slaveAddress1 must be provided. The other parameters are optional for operation. To initialize the driver, call Cy_SCB_EZI2C_Init function providing a pointer to the populated cy_stc_scb_ezi2c_config_t structure and the allocated cy_stc_scb_ezi2c_context_t structure.

/* Allocate context for EZI2C operation */
/* Populate configuration structure */
const cy_stc_scb_ezi2c_config_t ezI2cConfig =
{
.slaveAddress1 = 0x08U,
.slaveAddress2 = 0x00U,
.subAddressSize = CY_SCB_EZI2C_SUB_ADDR8_BITS,
.enableWakeFromSleep = false,
};
/* Configure EZI2C slave */
(void) Cy_SCB_EZI2C_Init(SCB3, &ezI2cConfig, &ezI2cContext);
cy_en_scb_ezi2c_num_of_addr_t numberOfAddresses
The number of supported addresses either.
Definition: cy_scb_ezi2c.h:314
EZI2C slave configuration structure.
Definition: cy_scb_ezi2c.h:312
EZI2C slave context structure.
Definition: cy_scb_ezi2c.h:341
@ CY_SCB_EZI2C_SUB_ADDR8_BITS
Sub-address is 8 bits
Definition: cy_scb_ezi2c.h:281
@ CY_SCB_EZI2C_ONE_ADDRESS
Only one address.
Definition: cy_scb_ezi2c.h:274
cy_en_scb_ezi2c_status_t Cy_SCB_EZI2C_Init(CySCB_Type *base, cy_stc_scb_ezi2c_config_t const *config, cy_stc_scb_ezi2c_context_t *context)
Initializes the SCB for the EZI2C operation.
Definition: cy_scb_ezi2c.c:74

Set up the EZI2C slave buffer before enabling its operation by using Cy_SCB_EZI2C_SetBuffer1 for the primary slave address and Cy_SCB_EZI2C_SetBuffer2 for the secondary (if the secondary is enabled).

/* Allocate buffer for EZI2C operation */
#define BUFFER_SIZE (128UL)
uint8_t bufferAddr1[BUFFER_SIZE];
/* Configure buffer for communication with master */
Cy_SCB_EZI2C_SetBuffer1(SCB3, bufferAddr1, BUFFER_SIZE, BUFFER_SIZE, &ezI2cContext);
void Cy_SCB_EZI2C_SetBuffer1(CySCB_Type const *base, uint8_t *buffer, uint32_t size, uint32_t rwBoundary, cy_stc_scb_ezi2c_context_t *context)
Sets up the data buffer to be exposed to the I2C master on the primary slave address request.
Definition: cy_scb_ezi2c.c:619

Assign and Configure Pins

Only dedicated SCB pins can be used for I2C operation. The HSIOM register must be configured to connect dedicated SCB I2C pins to the SCB block. Also the I2C pins must be configured in Open-Drain, Drives Low mode (this pin configuration implies usage of external pull-up resistors):

/* Assign pins for EZI2C on SCB0: P8[0] and P8[1] */
#define EZI2C_PORT (P8_0_PORT)
#define EZI2C_SCL_NUM (P8_0_NUM)
#define EZI2C_SDA_NUM (P8_1_NUM)
/* Connect SCB0 I2C function to pins */
Cy_GPIO_SetHSIOM(EZI2C_PORT, EZI2C_SCL_NUM, P8_0_SCB0_I2C_SCL);
Cy_GPIO_SetHSIOM(EZI2C_PORT, EZI2C_SDA_NUM, P8_1_SCB0_I2C_SDA);
/* Configure pins for I2C operation */
Cy_GPIO_SetDrivemode(EZI2C_PORT, EZI2C_SCL_NUM, CY_GPIO_DM_OD_DRIVESLOW);
Cy_GPIO_SetDrivemode(EZI2C_PORT, EZI2C_SDA_NUM, CY_GPIO_DM_OD_DRIVESLOW);
#define CY_GPIO_DM_OD_DRIVESLOW
Open Drain, Drives Low.
Definition: cy_gpio.h:518
__STATIC_INLINE void Cy_GPIO_SetDrivemode(GPIO_PRT_Type *base, uint32_t pinNum, uint32_t value)
Configures the pin output buffer drive mode and input buffer enable.
Definition: cy_gpio.h:1284
__STATIC_INLINE void Cy_GPIO_SetHSIOM(GPIO_PRT_Type *base, uint32_t pinNum, en_hsiom_sel_t value)
Configures the HSIOM connection to the pin.
Definition: cy_gpio.h:923
Note
The alternative pins configuration is Resistive Pull-ups which implies usage internal pull-up resistors. This configuration is not recommended because resistor value is fixed and cannot be used for all supported data rates. Refer to device datasheet parameter RPULLUP for resistor value specifications.

Assign Clock Divider

A clock source must be connected to the SCB block to oversample input and output signals, in this document this clock will be referred as clk_scb. You must use one of the 8-bit or 16-bit dividers. Use the SysClk (System Clock) driver API to do this.

/* Assign divider type and number for EZI2C */
#define EZI2C_CLK_DIV_TYPE (CY_SYSCLK_DIV_8_BIT)
#define EZI2C_CLK_DIV_NUMBER (0UL)
/* Connect assigned divider to be a clock source for EZI2C */
Cy_SysClk_PeriphAssignDivider(PCLK_SCB3_CLOCK_SCB_EN, EZI2C_CLK_DIV_TYPE, EZI2C_CLK_DIV_NUMBER);
cy_en_sysclk_status_t Cy_SysClk_PeriphAssignDivider(en_clk_dst_t ipBlock, cy_en_divider_types_t dividerType, uint32_t dividerNum)
Assigns a programmable divider to a selected IP block, such as a TCPWM or SCB.
Definition: cy_sysclk_v2.c:2175

Configure Data Rate

To get EZI2C slave to operate at the desired data rate, the clk_scb must be fast enough to provide sufficient oversampling. Use the SysClk (System Clock) driver API to do this.

Refer to the technical reference manual (TRM) section I2C sub-section Oversampling and Bit Rate to get information about how to configure the I2C to run at the desired data rate.

/* EZI2C slave desired data rate is 400 kbps.
* To support this data rate the clk_scb frequency must be in range 7.82 – 15.38 MHz.
* Find clk_scb valid ranges in TRM section I2C sub-section Oversampling and Bit Rate.
* For clk_peri = 50 MHz, select divider value 4 and get clk_scb = (50 MHz / 4) = 12.5 MHz.
* This clock frequency meets requirements above.
*/
Cy_SysClk_PeriphSetDivider (EZI2C_CLK_DIV_TYPE, EZI2C_CLK_DIV_NUMBER, 3u);
Cy_SysClk_PeriphEnableDivider(EZI2C_CLK_DIV_TYPE, EZI2C_CLK_DIV_NUMBER);
cy_en_sysclk_status_t Cy_SysClk_PeriphEnableDivider(cy_en_divider_types_t dividerType, uint32_t dividerNum)
Enables the selected divider.
Definition: cy_sysclk_v2.c:2189
cy_en_sysclk_status_t Cy_SysClk_PeriphSetDivider(cy_en_divider_types_t dividerType, uint32_t dividerNum, uint32_t dividerValue)
Sets one of the programmable clock dividers.
Definition: cy_sysclk_v2.c:2142

Configure Interrupt

The interrupt is mandatory for the EZI2C slave operation. The Cy_SCB_EZI2C_Interrupt function must be called in the interrupt handler for the selected SCB instance. Also, this interrupt must be enabled in the NVIC or it will not work.

/* Implement ISR for EZI2C */
void EZI2C_Isr(void)
{
Cy_SCB_EZI2C_Interrupt(SCB3, &ezI2cContext);
}
void Cy_SCB_EZI2C_Interrupt(CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context)
This is the interrupt function for the SCB configured in the EZI2C mode.
Definition: cy_scb_ezi2c.c:772
/* Assign EZI2C interrupt number and priority */
#define EZI2C_INTR_NUM scb_3_interrupt_IRQn
#define EZI2C_INTR_PRIORITY (7UL)
/* Populate configuration structure (code specific for CM4) */
const cy_stc_sysint_t ezI2cIntrConfig =
{
.intrSrc = EZI2C_INTR_NUM,
.intrPriority = EZI2C_INTR_PRIORITY,
};
/* Hook interrupt service routine and enable interrupt */
(void) Cy_SysInt_Init(&ezI2cIntrConfig, &EZI2C_Isr);
NVIC_EnableIRQ(EZI2C_INTR_NUM);
IRQn_Type intrSrc
Interrupt source.
Definition: cy_sysint.h:227
Initialization configuration structure for a single interrupt channel.
Definition: cy_sysint.h:225
cy_en_sysint_status_t Cy_SysInt_Init(const cy_stc_sysint_t *config, cy_israddress userIsr)
Initializes the referenced interrupt by setting the priority and the interrupt vector.
Definition: cy_sysint_v2.c:80

Enable EZI2C slave

Finally, enable the EZI2C slave operation by calling Cy_SCB_EZI2C_Enable. Now the I2C device responds to the assigned address.

/* Enable EZI2C to operate */
/* Enable global interrupts */
__enable_irq();
__STATIC_INLINE void Cy_SCB_EZI2C_Enable(CySCB_Type *base)
Enables the SCB block for the EZI2C operation.
Definition: cy_scb_ezi2c.h:547

Common Use Cases

The EZI2C slave operation might not require calling any EZI2C slave function because the I2C master is able to access the slave buffer. The application can directly access it as well. Note that this is an application-level task to ensure the buffer content integrity.

Master Write operation

This operation starts with sending a base address that is one or two bytes, depending on the sub-address size configuration. This base address is retained and will be used for later read operations. Following the base address, there is a sequence of bytes written into the buffer starting from the base address location. The buffer index is incremented for each written byte, but this does not affect the base address that is retained. The length of a write operation is limited by the maximum buffer read/write region size.
When a master attempts to write outside the read/write region or past the end of the buffer, the last byte is NACKed.

Master Read operation

This operation always starts from the base address set by the most recent write operation. The buffer index is incremented for each read byte. Two sequential read operations start from the same base address no matter how many bytes are read. The length of a read operation is not limited by the maximum size of the data buffer. The EZI2C slave returns 0xFF bytes if the read operation passes the end of the buffer.
Typically, a read operation requires the base address to be updated before starting the read. In this case, the write and read operations must be combined together.

The I2C master may use the ReStart or Stop/Start conditions to combine the operations. The write operation sets only the base address and the following read operation will start from the new base address. In cases where the base address remains the same, there is no need for a write operation.

Low Power Support

The EZI2C slave provides the callback functions to handle power mode transition. The callback Cy_SCB_EZI2C_DeepSleepCallback must be called during execution of Cy_SysPm_CpuEnterDeepSleep; Cy_SCB_EZI2C_HibernateCallback must be called during execution of Cy_SysPm_SystemEnterHibernate. To trigger the callback execution, the callback must be registered before calling the power mode transition function. Refer to SysPm (System Power Management) driver for more information about power mode transitions and callback registration.

The EZI2C configured to support two addresses can wakeup the device on address match to NACK not supported address. This happens because the hardware address-match-logic uses address bit masking to support to two addresses. The address mask defines which bits in the address are treated as non-significant while performing an address match. One non-significant bit results in two matching addresses; two bits will match 4 and so on. If the two addresses differ by more than a single bit, then the extra addresses that will pass the hardware match and wakeup the device from Deep Sleep mode. Then firmware address matching will to generate a NAK. Due to this reason, it is preferable to select a secondary address that is different from the primary by one bit. The address mask in this case makes one bit non-significant. For example:

API Reference

 Macros
 
 Functions
 
 Data Structures
 
 Enumerated Types