/** * MIT License * * Copyright (c) 2018 Infineon Technologies AG * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE * * * \file ifx_i2c_physical_layer.c * * \brief This file implements the IFX I2C Physical Layer. * * \addtogroup grIFXI2C * @{ */ /*********************************************************************************************************************** * HEADER FILES **********************************************************************************************************************/ #include "optiga/ifx_i2c/ifx_i2c_physical_layer.h" #include "optiga/pal/pal_os_event.h" /// @cond hidden /*********************************************************************************************************************** * MACROS **********************************************************************************************************************/ // Physical Layer Register addresses #define PL_REG_DATA (0x80) #define PL_REG_DATA_REG_LEN (0x81) #define PL_REG_I2C_STATE (0x82) #define PL_REG_BASE_ADDR (0x83) #define PL_REG_MAX_SCL_FREQU (0x84) #define PL_REG_SOFT_RESET (0x88) #define PL_REG_I2C_MODE (0x89) // Physical Layer Register lengths #define PL_REG_LEN_I2C_STATE (4) #define PL_REG_LEN_MAX_SCL_FREQU (4) #define PL_REG_LEN_I2C_MODE (2) #define PL_REG_LEN_DATA_REG_LEN (2) #define PL_REG_LEN_SOFT_RESET (2) #define PL_REG_LEN_BASE_ADDR (2) // Physical Layer State Register masks #define PL_REG_I2C_STATE_RESPONSE_READY (0x40) #define PL_REG_I2C_STATE_SOFT_RESET (0x08) // Physical Layer low level interface constants #define PL_ACTION_READ_REGISTER (0x01) #define PL_ACTION_WRITE_REGISTER (0x02) #define PL_I2C_CMD_WRITE (0x01) #define PL_I2C_CMD_READ (0x02) // Physical Layer high level interface constants #define PL_ACTION_WRITE_FRAME (0x01) #define PL_ACTION_READ_FRAME (0x02) #define PL_STATE_UNINIT (0x00) #define PL_STATE_INIT (0x01) #define PL_STATE_READY (0x02) #define PL_STATE_DATA_AVAILABLE (0x03) #define PL_STATE_RXTX (0x04) #define PL_STATE_SOFT_RESET (0x05) //Physical Layer negotiation constants #define PL_INIT_SET_DATA_REG_LEN (0x11) #define PL_INIT_GET_DATA_REG_LEN (0x22) #define PL_INIT_GET_FREQ_REG (0x33) #define PL_INIT_SET_FREQ_REG (0x44) #define PL_INIT_READ_FREQ (0x55) #define PL_INIT_VERIFY_FREQ (0x66) #define PL_INIT_AGREE_FREQ (0x77) #define PL_INIT_VERIFY_DATA_REG (0x88) #define PL_INIT_GET_STATUS_REG (0x99) #define PL_INIT_DONE (0xAA) #define PL_INIT_SET_FREQ_DEFAULT (0xBB) //Physical layer soft reset states #define PL_RESET_INIT (0xA1) #define PL_RESET_WRITE (0xA2) #define PL_RESET_STARTUP (0xA3) #define PL_REG_I2C_MODE_PERSISTANT (0x80) #define PL_REG_I2C_MODE_SM_FM (0x03) #define PL_REG_I2C_MODE_FM_PLUS (0x04) #define PL_SM_FM_MAX_FREQUENCY (0x190) #define PL_DEFAULT_FREQUENCY (0x64) #define PL_REG_BASE_ADDR_PERSISTANT (0x80) #define PL_REG_BASE_ADDR_VOLATILE (0x00) // Physical Layer Base Address Register mask #define PL_REG_I2C_BASE_ADDRESS_MASK (0x7F) // Setup debug log statements #if IFX_I2C_LOG_PL == 1 #include "common/Log_api.h" #define LOG_PL(args...) ifx_debug_log(IFX_I2C_LOG_ID_PL, args) #else #define LOG_PL(...) //printf(__VA_ARGS__) #endif /*********************************************************************************************************************** * ENUMS **********************************************************************************************************************/ /*********************************************************************************************************************** * DATA STRUCTURES ***********************************************************************************************************************/ /*********************************************************************************************************************** * GLOBAL ***********************************************************************************************************************/ static host_lib_status_t pal_event_status; /*********************************************************************************************************************** * LOCAL ROUTINES ***********************************************************************************************************************/ /// Physical Layer low level interface function static void ifx_i2c_pl_read_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len); /// Physical Layer low level interface function static void ifx_i2c_pl_write_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len, const uint8_t* p_content); /// Physical Layer high level interface timer callback (Status register polling) static void ifx_i2c_pl_status_poll_callback(void *p_ctx); /// Physical Layer intermediate state machine (Negotiation with slave) static void ifx_i2c_pl_negotiation_event_handler(void *p_input_ctx); /// Physical Layer intermediate state machine(Set bit rate) static host_lib_status_t ifx_i2c_pl_set_bit_rate(ifx_i2c_context_t *p_ctx, uint16_t bitrate); /// Physical Layer intermediate state machine (soft reset) static void ifx_i2c_pl_soft_reset(ifx_i2c_context_t *p_ctx); /// Physical Layer high level interface state machine (read/write frames) static void ifx_i2c_pl_frame_event_handler(ifx_i2c_context_t *p_ctx,host_lib_status_t event); /// Physical Layer low level interface timer callback (I2C Nack/Busy polling) static void ifx_i2c_pal_poll_callback(void *p_ctx); /// Physical Layer low level guard time callback static void ifx_i2c_pl_guard_time_callback(void *p_ctx); /// Physical Layer low level interface state machine (read/write registers) static void ifx_i2c_pl_pal_event_handler(void *p_ctx, host_lib_status_t event); /// Physical layer low level event handler for set slave address static void ifx_i2c_pl_pal_slave_addr_event_handler(void *p_input_ctx, host_lib_status_t event); /// @endcond /*********************************************************************************************************************** * API PROTOTYPES **********************************************************************************************************************/ /// Physical Layer high level interface function host_lib_status_t ifx_i2c_pl_init(ifx_i2c_context_t *p_ctx,ifx_i2c_event_handler_t handler) { LOG_PL("[IFX-PL]: Init\n"); p_ctx->pl.upper_layer_event_handler = handler; p_ctx->pl.frame_state = PL_STATE_UNINIT; p_ctx->pl.negotiate_state = PL_INIT_SET_FREQ_DEFAULT; p_ctx->p_pal_i2c_ctx->slave_address = p_ctx->slave_address; p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = (void*)ifx_i2c_pl_pal_event_handler; p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT; if(TRUE == p_ctx->do_pal_init) { // Initialize I2C driver if (PAL_STATUS_SUCCESS != pal_i2c_init(p_ctx->p_pal_i2c_ctx)) { return IFX_I2C_STACK_ERROR; } } // Set Physical Layer internal state if(p_ctx->pl.request_soft_reset == (uint8_t)TRUE) { //Set the soft reset request to initial state to read register p_ctx->pl.request_soft_reset = PL_INIT_GET_STATUS_REG; p_ctx->pl.frame_state = PL_STATE_SOFT_RESET; } else { p_ctx->pl.frame_state = PL_STATE_INIT; } ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS); return IFX_I2C_STACK_SUCCESS; } /// Physical Layer high level interface function host_lib_status_t ifx_i2c_pl_send_frame(ifx_i2c_context_t *p_ctx,uint8_t* p_frame, uint16_t frame_len) { // Physical Layer must be idle, set requested action if (p_ctx->pl.frame_state != PL_STATE_INIT && p_ctx->pl.frame_state != PL_STATE_READY) { return IFX_I2C_STACK_ERROR; } p_ctx->pl.frame_action = PL_ACTION_WRITE_FRAME; // Store reference to frame for sending it later p_ctx->pl.p_tx_frame = p_frame; p_ctx->pl.tx_frame_len = frame_len; ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS); return IFX_I2C_STACK_SUCCESS; } /// Physical Layer high level interface function host_lib_status_t ifx_i2c_pl_receive_frame(ifx_i2c_context_t *p_ctx) { // Physical Layer must be idle, set requested action if (p_ctx->pl.frame_state != PL_STATE_INIT && p_ctx->pl.frame_state != PL_STATE_READY) { return IFX_I2C_STACK_ERROR; } p_ctx->pl.frame_action = PL_ACTION_READ_FRAME; ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS); return IFX_I2C_STACK_SUCCESS; } host_lib_status_t ifx_i2c_pl_write_slave_address(ifx_i2c_context_t *p_ctx, uint8_t slave_address, uint8_t persistent) { host_lib_status_t status = IFX_I2C_STACK_ERROR; app_event_handler_t * temp_upper_layer_event_handler; /// @cond hidden #define PAL_WRITE_INIT_STATUS (0x00FF) #define ADDRESS_OFFSET (0x02) #define BASE_ADDRESS_REG_OFFSET (0x00) #define MODE_OFFSET (0x01) /// @endcond //lint --e{611} suppress "void* function pointer is type casted to app_event_handler_t type" //ifx i2c wrapper api for setting slave address in synchronous. hence the event handler is backed up. temp_upper_layer_event_handler = (app_event_handler_t *)(p_ctx->p_pal_i2c_ctx->upper_layer_event_handler); //since the lower level APIs are asynchronous, a temporary event handler for set slave address is assigned p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = (void*)ifx_i2c_pl_pal_slave_addr_event_handler; p_ctx->pl.buffer[BASE_ADDRESS_REG_OFFSET] = PL_REG_BASE_ADDR; p_ctx->pl.buffer[MODE_OFFSET] = PL_REG_BASE_ADDR_VOLATILE; //supported base addresses are 0x00 - 0x7F. Hence 8th bit is ignored p_ctx->pl.buffer[ADDRESS_OFFSET] = slave_address & PL_REG_I2C_BASE_ADDRESS_MASK; p_ctx->pl.buffer_tx_len = 1 + PL_REG_LEN_BASE_ADDR; if(PL_REG_BASE_ADDR_VOLATILE != persistent) { p_ctx->pl.buffer[MODE_OFFSET] = PL_REG_BASE_ADDR_PERSISTANT; } p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT; while(p_ctx->pl.retry_counter) { pal_event_status = PAL_WRITE_INIT_STATUS; //lint --e{534} suppress "Return value is not required to be checked" pal_i2c_write(p_ctx->p_pal_i2c_ctx,p_ctx->pl.buffer, p_ctx->pl.buffer_tx_len); while(PAL_WRITE_INIT_STATUS == pal_event_status){}; if(PAL_I2C_EVENT_SUCCESS == pal_event_status) { break; } p_ctx->pl.retry_counter--; pal_os_timer_delay_in_milliseconds(PL_POLLING_INVERVAL_US); } if(PAL_I2C_EVENT_SUCCESS == pal_event_status) { p_ctx->p_pal_i2c_ctx->slave_address = p_ctx->pl.buffer[ADDRESS_OFFSET]; if(PL_REG_BASE_ADDR_VOLATILE != persistent) { p_ctx->slave_address = p_ctx->pl.buffer[ADDRESS_OFFSET]; } status = IFX_I2C_STACK_SUCCESS; } //restoring the backed up event handler p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = temp_upper_layer_event_handler; /// @cond hidden #undef PAL_WRITE_INIT_STATUS #undef ADDRESS_OFFSET #undef BASE_ADDRESS_REG_OFFSET #undef MODE_OFFSET /// @endcond return status; } static void ifx_i2c_pl_read_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len) { LOG_PL("[IFX-PL]: Read register %x len %d\n", reg_addr, reg_len); // Prepare transmit buffer to write register address p_ctx->pl.buffer[0] = reg_addr; p_ctx->pl.buffer_tx_len = 1; // Set low level interface variables and start transmission p_ctx->pl.buffer_rx_len = reg_len; p_ctx->pl.register_action = PL_ACTION_READ_REGISTER; p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT; p_ctx->pl.i2c_cmd = PL_I2C_CMD_WRITE; //lint --e{534} suppress "Return value is not required to be checked" pal_i2c_write(p_ctx->p_pal_i2c_ctx,p_ctx->pl.buffer, p_ctx->pl.buffer_tx_len); } static void ifx_i2c_pl_write_register(ifx_i2c_context_t *p_ctx,uint8_t reg_addr, uint16_t reg_len, const uint8_t* p_content) { LOG_PL("[IFX-PL]: Write register %x len %d\n", reg_addr, reg_len); // Prepare transmit buffer to write register address and content p_ctx->pl.buffer[0] = reg_addr; memcpy(p_ctx->pl.buffer + 1, p_content, reg_len); p_ctx->pl.buffer_tx_len = 1 + reg_len; // Set Physical Layer low level interface variables and start transmission p_ctx->pl.register_action = PL_ACTION_WRITE_REGISTER; p_ctx->pl.retry_counter = PL_POLLING_MAX_CNT; p_ctx->pl.i2c_cmd = PL_I2C_CMD_WRITE; //lint --e{534} suppress "Return value is not required to be checked" pal_i2c_write(p_ctx->p_pal_i2c_ctx,p_ctx->pl.buffer, p_ctx->pl.buffer_tx_len); } static void ifx_i2c_pl_status_poll_callback(void *p_ctx) { LOG_PL("[IFX-PL]: Status poll Timer elapsed -> Read STATUS register\n"); ifx_i2c_pl_read_register((ifx_i2c_context_t*)p_ctx,PL_REG_I2C_STATE, PL_REG_LEN_I2C_STATE); } static host_lib_status_t ifx_i2c_pl_set_bit_rate(ifx_i2c_context_t *p_ctx, uint16_t bitrate) { host_lib_status_t status; void* pal_ctx_upper_layer_handler; // Save upper layer context in pal pal_ctx_upper_layer_handler = p_ctx->p_pal_i2c_ctx->upper_layer_event_handler; // Pass context as NULL to avoid callback invocation p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = NULL; status = pal_i2c_set_bitrate(p_ctx->p_pal_i2c_ctx , bitrate); // Restore callback p_ctx->p_pal_i2c_ctx->upper_layer_event_handler = pal_ctx_upper_layer_handler; if(PAL_I2C_EVENT_SUCCESS != status) { if (p_ctx->pl.retry_counter--) { LOG_PL("[IFX-PL]: Set bit rate failed, Retry setting.\n"); pal_os_event_register_callback_oneshot(ifx_i2c_pl_negotiation_event_handler,((void*)p_ctx),PL_POLLING_INVERVAL_US); status = IFX_I2C_STACK_BUSY; } else { status = IFX_I2C_STACK_ERROR; } } else { status = IFX_I2C_STACK_SUCCESS; } return status; } static void ifx_i2c_pl_negotiation_event_handler(void *p_input_ctx) { host_lib_status_t event = (uint8_t)IFX_I2C_STACK_ERROR; uint8_t continue_negotiation; ifx_i2c_context_t* p_ctx = (ifx_i2c_context_t*)p_input_ctx; uint8_t i2c_mode_value[2]; uint8_t max_frame_size[2] = { (uint8_t)(p_ctx->frame_size >> 8), (uint8_t)(p_ctx->frame_size) }; uint16_t buffer_len = 0; uint16_t slave_frequency; uint16_t slave_frame_len; uint8_t* p_buffer = NULL; do { continue_negotiation = FALSE; LOG_PL("[IFX-PL]: Negotiation started\n"); switch(p_ctx->pl.negotiate_state) { // Set initial frequency to PL_DEFAULT_FREQUENCY to be able to negotiate with slave case PL_INIT_SET_FREQ_DEFAULT: { // Default frequency set to master event = ifx_i2c_pl_set_bit_rate(p_input_ctx,PL_DEFAULT_FREQUENCY); if(IFX_I2C_STACK_SUCCESS == event) { p_ctx->pl.negotiate_state = PL_INIT_GET_FREQ_REG; continue_negotiation = TRUE; } else if (IFX_I2C_STACK_ERROR == event) { p_ctx->pl.negotiate_state = PL_INIT_DONE; p_buffer = NULL; buffer_len = 0; } } break; // Read the current Max frequency supported by slave case PL_INIT_GET_FREQ_REG: { p_ctx->pl.negotiate_state = PL_INIT_SET_FREQ_REG; ifx_i2c_pl_read_register(p_ctx,PL_REG_MAX_SCL_FREQU, PL_REG_LEN_MAX_SCL_FREQU); } break; // Set the I2C mode register case PL_INIT_SET_FREQ_REG: { slave_frequency = (p_ctx->pl.buffer[2] << 8) | p_ctx->pl.buffer[3]; i2c_mode_value[0] = PL_REG_I2C_MODE_PERSISTANT; if((p_ctx->frequency > PL_SM_FM_MAX_FREQUENCY)&&(slave_frequency<=PL_SM_FM_MAX_FREQUENCY)) { //Change to FM+ mode if slave's current supported frequency is below user's requested frequency i2c_mode_value[1] = PL_REG_I2C_MODE_FM_PLUS; p_ctx->pl.negotiate_state = PL_INIT_READ_FREQ; ifx_i2c_pl_write_register(p_ctx,PL_REG_I2C_MODE, PL_REG_LEN_I2C_MODE, i2c_mode_value); } else if((p_ctx->frequency <= PL_SM_FM_MAX_FREQUENCY)&&(slave_frequency>PL_SM_FM_MAX_FREQUENCY)) { //Change to SM&FM mode if slave's current supported frequency is above user's requested frequency i2c_mode_value[1] = PL_REG_I2C_MODE_SM_FM; p_ctx->pl.negotiate_state = PL_INIT_READ_FREQ; ifx_i2c_pl_write_register(p_ctx,PL_REG_I2C_MODE, PL_REG_LEN_I2C_MODE, i2c_mode_value); } else { p_ctx->pl.negotiate_state = PL_INIT_VERIFY_FREQ; continue_negotiation = TRUE; } } break; // After setting I2C mode register, read the slave's supported frequency case PL_INIT_READ_FREQ: { p_ctx->pl.negotiate_state = PL_INIT_VERIFY_FREQ; ifx_i2c_pl_read_register(p_ctx,PL_REG_MAX_SCL_FREQU, PL_REG_LEN_MAX_SCL_FREQU); } break; // Verify the requested frequency and slave's supported frequency case PL_INIT_VERIFY_FREQ: { slave_frequency = (p_ctx->pl.buffer[2] << 8) | p_ctx->pl.buffer[3]; if(p_ctx->frequency > slave_frequency) { LOG_PL("[IFX-PL]: Unexpected frequency in MAX_SCL_FREQU\n"); p_buffer = NULL; buffer_len = 0; p_ctx->pl.negotiate_state = PL_INIT_DONE; } else { p_ctx->pl.negotiate_state = PL_INIT_AGREE_FREQ; } continue_negotiation = TRUE; } break; // Frequency negotiated, Set frequency at master case PL_INIT_AGREE_FREQ: { // Frequency negotiation between master and slave is complete event = ifx_i2c_pl_set_bit_rate(p_input_ctx, p_ctx->frequency); if(IFX_I2C_STACK_SUCCESS == event) { p_ctx->pl.negotiate_state = PL_INIT_SET_DATA_REG_LEN; continue_negotiation = TRUE; } else if (IFX_I2C_STACK_ERROR == event) { p_ctx->pl.negotiate_state = PL_INIT_DONE; p_buffer = NULL; buffer_len = 0; } } break; // Start frame length negotiation by writing the requested frame length case PL_INIT_SET_DATA_REG_LEN: { p_ctx->pl.negotiate_state = PL_INIT_GET_DATA_REG_LEN; ifx_i2c_pl_write_register(p_ctx,PL_REG_DATA_REG_LEN, sizeof(max_frame_size), max_frame_size); } break; // Read the frame length to verify case PL_INIT_GET_DATA_REG_LEN: { p_ctx->pl.negotiate_state = PL_INIT_VERIFY_DATA_REG; ifx_i2c_pl_read_register(p_ctx,PL_REG_DATA_REG_LEN,PL_REG_LEN_DATA_REG_LEN); } break; // Check is slave accepted the new frame length case PL_INIT_VERIFY_DATA_REG: { p_ctx->pl.negotiate_state = PL_INIT_DONE; slave_frame_len = (p_ctx->pl.buffer[0] << 8) | p_ctx->pl.buffer[1]; // Error if slave's frame length is more than requested frame length if(p_ctx->frame_size >= slave_frame_len) { p_ctx->frame_size = slave_frame_len; event = IFX_I2C_STACK_SUCCESS; } p_buffer = NULL; buffer_len = 0; continue_negotiation = TRUE; } break; case PL_INIT_DONE: { if(IFX_I2C_STACK_SUCCESS == event) { p_ctx->pl.frame_state = PL_STATE_READY; } else { p_ctx->pl.frame_state = PL_STATE_UNINIT; } // Negotiation between master and slave is complete p_ctx->pl.upper_layer_event_handler(p_ctx,event, p_buffer, buffer_len); } break; default: break; } }while(continue_negotiation); } static void ifx_i2c_pl_frame_event_handler(ifx_i2c_context_t *p_ctx,host_lib_status_t event) { uint16_t frame_size; if (event != IFX_I2C_STACK_SUCCESS) { p_ctx->pl.frame_state = PL_STATE_READY; // I2C read or write failed, report to upper layer p_ctx->pl.upper_layer_event_handler(p_ctx,event, 0, 0); } else { switch(p_ctx->pl.frame_state) { // Perform soft reset case PL_STATE_SOFT_RESET: { ifx_i2c_pl_soft_reset(p_ctx); } break; // Negotiate frame and frequency with slave case PL_STATE_INIT: { ifx_i2c_pl_negotiation_event_handler(p_ctx); } break; // Check status of slave data case PL_STATE_READY: { // Start polling status register p_ctx->pl.frame_state = PL_STATE_DATA_AVAILABLE; ifx_i2c_pl_read_register(p_ctx,PL_REG_I2C_STATE, PL_REG_LEN_I2C_STATE); } break; // Do read/write frame case PL_STATE_DATA_AVAILABLE: { // Read frame, if response is ready. Ignore busy flag if ((p_ctx->pl.frame_action == PL_ACTION_READ_FRAME) && (p_ctx->pl.buffer[0] & PL_REG_I2C_STATE_RESPONSE_READY)) { frame_size = (p_ctx->pl.buffer[2] << 8) | p_ctx->pl.buffer[3]; if ((frame_size > 0) && (frame_size <= p_ctx->frame_size)) { p_ctx->pl.frame_state = PL_STATE_RXTX; ifx_i2c_pl_read_register(p_ctx,PL_REG_DATA, frame_size); } else { // Continue polling STATUS register if retry limit is not reached if ((pal_os_timer_get_time_in_milliseconds() - p_ctx->dl.frame_start_time) < p_ctx->dl.data_poll_timeout) { pal_os_event_register_callback_oneshot(ifx_i2c_pl_status_poll_callback, (void *)p_ctx, PL_DATA_POLLING_INVERVAL_US); } else { p_ctx->pl.frame_state = PL_STATE_READY; p_ctx->pl.upper_layer_event_handler(p_ctx,IFX_I2C_STACK_ERROR, 0, 0); } } } // Write frame is slave is not busy else if (p_ctx->pl.frame_action == PL_ACTION_WRITE_FRAME) { // Write frame if device is not busy, otherwise wait and poll STATUS again later p_ctx->pl.frame_state = PL_STATE_RXTX; ifx_i2c_pl_write_register(p_ctx,PL_REG_DATA, p_ctx->pl.tx_frame_len, (uint8_t*)p_ctx->pl.p_tx_frame); } // Continue checking the slave status register else { // Continue polling STATUS register if retry limit is not reached if ((pal_os_timer_get_time_in_milliseconds() - p_ctx->dl.frame_start_time) < p_ctx->dl.data_poll_timeout) { pal_os_event_register_callback_oneshot(ifx_i2c_pl_status_poll_callback, (void *)p_ctx, PL_DATA_POLLING_INVERVAL_US); } else { p_ctx->pl.frame_state = PL_STATE_READY; p_ctx->pl.upper_layer_event_handler(p_ctx,IFX_I2C_STACK_ERROR, 0, 0); } } } break; // Frame reading is complete case PL_STATE_RXTX: { // Writing/reading of frame to/from DATA register complete p_ctx->pl.frame_state = PL_STATE_READY; p_ctx->pl.upper_layer_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS, p_ctx->pl.buffer, p_ctx->pl.buffer_rx_len); } break; default: break; } } } static void ifx_i2c_pal_poll_callback(void *p_ctx) { ifx_i2c_context_t* p_local_ctx = (ifx_i2c_context_t *)p_ctx; if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_WRITE) { LOG_PL("[IFX-PL]: Poll Timer elapsed -> Restart TX\n"); //lint --e{534} suppress "Return value is not required to be checked" pal_i2c_write(p_local_ctx->p_pal_i2c_ctx, p_local_ctx->pl.buffer, p_local_ctx->pl.buffer_tx_len); } else if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_READ) { LOG_PL("[IFX-PL]: Poll Timer elapsed -> Restart Read Register -> Start TX\n"); //lint --e{534} suppress "Return value is not required to be checked" pal_i2c_read(p_local_ctx->p_pal_i2c_ctx,p_local_ctx->pl.buffer, p_local_ctx->pl.buffer_rx_len); } } static void ifx_i2c_pl_guard_time_callback(void *p_ctx) { ifx_i2c_context_t* p_local_ctx = (ifx_i2c_context_t*)p_ctx; if (p_local_ctx->pl.register_action == PL_ACTION_READ_REGISTER) { if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_WRITE) { LOG_PL("[IFX-PL]: GT done-> Start RX\n"); p_local_ctx->pl.i2c_cmd = PL_I2C_CMD_READ; //lint --e{534} suppress "Return value is not required to be checked" pal_i2c_read(p_local_ctx->p_pal_i2c_ctx,p_local_ctx->pl.buffer, p_local_ctx->pl.buffer_rx_len); } else if (p_local_ctx->pl.i2c_cmd == PL_I2C_CMD_READ) { LOG_PL("[IFX-PL]: GT done -> REG is read\n"); ifx_i2c_pl_frame_event_handler(p_local_ctx,IFX_I2C_STACK_SUCCESS); } } else if (p_local_ctx->pl.register_action == PL_ACTION_WRITE_REGISTER) { LOG_PL("[IFX-PL]: GT done -> REG written\n"); ifx_i2c_pl_frame_event_handler(p_local_ctx,IFX_I2C_STACK_SUCCESS); } } static void ifx_i2c_pl_pal_event_handler(void *p_ctx, host_lib_status_t event) { ifx_i2c_context_t* p_local_ctx = (ifx_i2c_context_t*)p_ctx; switch (event) { case PAL_I2C_EVENT_ERROR: case PAL_I2C_EVENT_BUSY: // Error event usually occurs when the device is in sleep mode and needs time to wake up if (p_local_ctx->pl.retry_counter--) { LOG_PL("[IFX-PL]: PAL Error -> Continue polling\n"); pal_os_event_register_callback_oneshot(ifx_i2c_pal_poll_callback,p_local_ctx,PL_POLLING_INVERVAL_US); } else { LOG_PL("[IFX-PL]: PAL Error -> Stop\n"); ifx_i2c_pl_frame_event_handler(p_local_ctx,IFX_I2C_FATAL_ERROR); } break; case PAL_I2C_EVENT_SUCCESS: LOG_PL("[IFX-PL]: PAL Success -> Wait Guard Time\n"); pal_os_event_register_callback_oneshot(ifx_i2c_pl_guard_time_callback,p_local_ctx,PL_GUARD_TIME_INTERVAL_US); break; default: break; } } static void ifx_i2c_pl_soft_reset(ifx_i2c_context_t *p_ctx) { uint8_t i2c_mode_value[2] = {0}; switch(p_ctx->pl.request_soft_reset) { case PL_INIT_GET_STATUS_REG: p_ctx->pl.request_soft_reset = PL_RESET_WRITE; //Read the status register to check if soft reset is supported ifx_i2c_pl_read_register(p_ctx, PL_REG_I2C_STATE, PL_REG_LEN_I2C_STATE); break; case PL_RESET_WRITE: //Mask for soft reset bit(5th bit) from the 1st byte of status register p_ctx->pl.buffer[0] &= PL_REG_I2C_STATE_SOFT_RESET; if(p_ctx->pl.buffer[0] == PL_REG_I2C_STATE_SOFT_RESET) { p_ctx->pl.request_soft_reset = PL_RESET_STARTUP; //Write 88 register with 0 value ifx_i2c_pl_write_register(p_ctx, PL_REG_SOFT_RESET, PL_REG_LEN_SOFT_RESET, i2c_mode_value); } else { //Soft reset is not supported by the slave p_ctx->pl.frame_state = PL_STATE_UNINIT; ifx_i2c_pl_frame_event_handler(p_ctx, IFX_I2C_STACK_ERROR); } break; case PL_RESET_STARTUP: p_ctx->pl.request_soft_reset= PL_RESET_INIT; pal_os_event_register_callback_oneshot((register_callback)ifx_i2c_pl_soft_reset, (void *)p_ctx, STARTUP_TIME_MSEC); break; case PL_RESET_INIT: p_ctx->pl.frame_state = PL_STATE_INIT; ifx_i2c_pl_frame_event_handler(p_ctx,IFX_I2C_STACK_SUCCESS); break; default: break; } } //lint --e{715} suppress "This is used for synchromous implementation, hence p_ctx not used" //lint --e{818} suppress "This is ignored as upper layer handler function prototype requires this argument" static void ifx_i2c_pl_pal_slave_addr_event_handler(void *p_ctx, host_lib_status_t event) { pal_event_status = event; }