diff --git a/os/hal/ports/SN32/LLD/SN32F2xx/I2C/I2C.c b/os/hal/ports/SN32/LLD/SN32F2xx/I2C/I2C.c deleted file mode 100644 index 53efe1baf1..0000000000 --- a/os/hal/ports/SN32/LLD/SN32F2xx/I2C/I2C.c +++ /dev/null @@ -1,368 +0,0 @@ -/******************** (C) COPYRIGHT 2017 SONiX ******************************* -* COMPANY: SONiX -* DATE: 2017/07 -* AUTHOR: SA1 -* IC: SN32F240B -* DESCRIPTION: I2C0 related functions. -*____________________________________________________________________________ -* REVISION Date User Description -* 1.0 2017/07/07 SA1 First release -* -*____________________________________________________________________________ -* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS -* WITH CODING INFORMATION REGARDING THEIR PRODUCTS TIME TO MARKET. -* SONiX SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL -* DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT OF SUCH SOFTWARE -* AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN -* IN CONNECTION WITH THEIR PRODUCTS. -*****************************************************************************/ - -/*_____ I N C L U D E S ____________________________________________________*/ -#include -#include -#include "I2C.h" - -/*_____ D E C L A R A T I O N S ____________________________________________*/ -uint8_t bI2C_RxFIFO[I2C_RX_FIFO_LENGTH]; -uint8_t bI2C_TxFIFO[I2C_TX_FIFO_LENGTH] = {0}; -uint8_t bI2C_RxFIFO_cnts, bI2C_Rx_cnts; -uint8_t bI2C_TxFIFO_cnts, bI2C_Tx_cnts; -uint8_t *bTX_ptr; -uint8_t EEPROM_ADR_H, EEPROM_ADR_L; -uint8_t EEPROM_WR; // 0 : write - // 1 : read -uint8_t Busy = 1, Error = 0; -uint8_t Read_Down = 0; -uint8_t Send_Address; -uint8_t temp = 0; -volatile uint8_t Timeout = 0; - - -/*_____ D E F I N I T I O N S ______________________________________________*/ - - -/*_____ M A C R O S ________________________________________________________*/ - - -/*_____ F U N C T I O N S __________________________________________________*/ -/***************************************************************************** -* Function : I2C_Init -* Description : Initialization of I2C -* Input : None -* Output : None -* Return : None -* Note : None -*****************************************************************************/ -void I2C_Init (void) -{ - SN_SYS1->AHBCLKEN_b.I2C0CLKEN = 1; //Enables HCLK for I2C0 - - //I2C speed - SN_I2C0->SCLHT = I2C0_SCLHT; - SN_I2C0->SCLLT = I2C0_SCLLT; - - SN_I2C0->CTRL_b.I2CEN = 1; //Enable I2C - - //===NVIC=== - NVIC_ClearPendingIRQ(I2C0_IRQn); - NVIC_EnableIRQ(I2C0_IRQn); -} -/***************************************************************************** -* Function : I2C_Start -* Description : transmit a START bit -* Input : None -* Output : None -* Return : None -* Note : None -*****************************************************************************/ -void I2C_Start(void) -{ - SN_I2C0->CTRL_b.STA = 1; -} -/***************************************************************************** -* Function : I2C_Stop -* Description : transmit a STOP condition in master mode -* Input : None -* Output : None -* Return : None -* Note : None -*****************************************************************************/ -void I2C_Stop(void) -{ - SN_I2C0->CTRL_b.STO = 1; -} -/***************************************************************************** -* Function : I2C_Read -* Description : read N Byte data from EEPROM -* Input : eeprom_adr - data word address -* : read_num - byte length -* Output : None -* Return : OK or Fail -* Note : None -*****************************************************************************/ -uint8_t I2C_Read(uint16_t eeprom_adr, uint8_t read_num) -{ - bI2C_Rx_cnts = 0; - - EEPROM_ADR_H = eeprom_adr >> 8; //data word address low byte - EEPROM_ADR_L = eeprom_adr & 0x00ff; //data word address high byte - - bI2C_RxFIFO_cnts = read_num; //byte length - - Busy = 1; - - EEPROM_WR = 0; //write - - I2C_Start(); //I2C start - - SysTick->CTRL = 0x7; //Enable SysTick timer and interrupt - - Send_Address = 1; //data word address setting flag - - while(Busy == 1 && Timeout == 0); - - SysTick->CTRL = 0x0; //Disable SysTick timer and interrupt - - if(Error == 1 || Timeout == 1) return FALSE; - - #if (EEPROM_less_than_32K == 0) - - SN_I2C0->TXDATA = EEPROM_ADR_H; //data word address high byte - - SysTick->CTRL = 0x7; //Enable SysTick timer and interrupt - - Busy = 1; - - while(Busy == 1 && Timeout == 0); - - SysTick->CTRL = 0x0; //Disable SysTick timer and interrupt - - if(Error == 1 || Timeout == 1) return FALSE; - - #endif - - SN_I2C0->TXDATA = EEPROM_ADR_L; //data word address low byte - - SysTick->CTRL = 0x7; //Enable SysTick timer and interrupt - - Busy = 1; - - while(Busy == 1 && Timeout == 0); - - SysTick->CTRL = 0x0; //Disable SysTick timer and interrupt - - if(Error == 1 || Timeout == 1) return FALSE; - - Read_Down = 0; - - Send_Address = 0; - - EEPROM_WR = 1; //read - - I2C_Start(); //I2C start - - SysTick->CTRL = 0x7; //Enable SysTick timer and interrupt - - while(Read_Down == 0 && Timeout == 0); - - SysTick->CTRL = 0x0; //Disable SysTick timer and interrupt - - Read_Down = 0; - - if(Error == 1 || Timeout == 1) return FALSE; - - return TRUE; -} -/***************************************************************************** -* Function : I2C_Write -* Description : write N Byte data to EEPROM -* Input : eeprom_adr - data word address -* : write_num - byte length -* Output : None -* Return : OK or Fail -* Note : None -*****************************************************************************/ -uint8_t I2C_Write(uint16_t eeprom_adr, uint8_t write_num) -{ - Timeout = 0; - - bI2C_Tx_cnts = 0; - - bTX_ptr = &bI2C_TxFIFO[0]; //write data buffer - - EEPROM_ADR_H = eeprom_adr >> 8; //data word address high byte - - EEPROM_ADR_L = eeprom_adr & 0x00ff; //data word address low byte - - bI2C_TxFIFO_cnts = write_num; //byte length - - Busy = 1; - - EEPROM_WR = 0; //write - - SysTick->CTRL = 0x7; //Enable SysTick timer and interrupt - - I2C_Start(); //I2C start - - Send_Address = 1; //data word address setting flag - - while(Busy == 1 && Timeout == 0); - - SysTick->CTRL = 0x0; //Disable SysTick timer and interrupt - - if(Error == 1 || Timeout == 1) return FALSE; - - #if (EEPROM_less_than_32K == 0) - - SN_I2C0->TXDATA = EEPROM_ADR_H; //data word address high byte - - SysTick->CTRL = 0x7; //Enable SysTick timer and interrupt - - Busy = 1; - - while(Busy == 1 && Timeout == 0); - - SysTick->CTRL = 0x0; //Disable SysTick timer and interrupt - - if(Error == 1 || Timeout == 1) return FALSE; - - #endif - - SN_I2C0->TXDATA = EEPROM_ADR_L; //data word address low byte - - SysTick->CTRL = 0x7; //Enable SysTick timer and interrupt - - Busy = 1; - - while(Busy == 1 && Timeout == 0); - - if(Error == 1 || Timeout == 1 ) return FALSE; - - SysTick->CTRL = 0x0; //Disable SysTick timer and interrupt - - Send_Address = 0; - - SN_I2C0->TXDATA = *bTX_ptr++; //write data - - SysTick->CTRL = 0x7; //Enable SysTick timer and interrupt - - Busy = 1; - - while(Busy == 1 && Timeout == 0); - - if(Error == 1 || Timeout == 1) return FALSE; - - SysTick->CTRL = 0x0; //Disable SysTick timer and interrupt - - Busy = 1; - - I2C_Stop(); - - SysTick->CTRL = 0x7; //Enable SysTick timer and interrupt - - while(Busy == 1 && Timeout == 0); - - if(Error == 1 || Timeout == 1) return FALSE; - - SysTick->CTRL = 0x0; //Disable SysTick timer and interrupt - - return TRUE; -} - -/***************************************************************************** -* Function : I2C_IRQHandler -* Description : I2C interrupt service routine -* Input : None -* Output : None -* Return : None -* Note : None -*****************************************************************************/ -__irq void I2C0_IRQHandler(void) -{ - if(((SN_I2C0->STAT) & (mskI2C_LOST_ARB_LOST_ARBITRATION)) == Lost_Arbitration) - { - SN_I2C0->STAT_b.I2CIF = 1; - SN_I2C0->CTRL_b.I2CEN = 0; //Disable I2C - SN_I2C0->CTRL_b.I2CEN = 1; //Enable I2C - I2C_Start(); //Re-start - } - - /* Stop Done */ - else if(((SN_I2C0->STAT) & (mskI2C_STA_MASTER_STA_STO)) == STOP_DONE) - { - Busy = 0; - SN_I2C0->STAT_b.I2CIF = 1; - if(EEPROM_WR == 1) - Read_Down = 1; - } - else - { - SN_I2C0->STAT_b.I2CIF = 1; - - switch (SN_I2C0->STAT) - { - case (Lost_Arbitration | mskI2C_MST_MASTER): - I2C_Start(); - break; - - /* RX with ACK/NACK transfer is down */ - case (RX_DONE | mskI2C_MST_MASTER): - bI2C_RxFIFO[bI2C_Rx_cnts++] = SN_I2C0->RXDATA; - if(bI2C_Rx_cnts < (bI2C_RxFIFO_cnts - 1)) - SN_I2C0->CTRL_b.ACK = 1; - else if(bI2C_Rx_cnts == (bI2C_RxFIFO_cnts - 1)) - SN_I2C0->CTRL_b.NACK = 1; - else if(bI2C_Rx_cnts == bI2C_RxFIFO_cnts) - I2C_Stop(); - Busy = 0; - break; - - /* SLA+W or Data has been transmitted and ACK has been received */ - case (ACK_DONE | mskI2C_MST_MASTER): - if(EEPROM_WR == 1) - { - Busy = 0; - if(bI2C_RxFIFO_cnts == 1) - SN_I2C0->CTRL_b.NACK = 1; - else - SN_I2C0->CTRL_b.ACK = 1; - } - if(EEPROM_WR == 0) - { - if(Send_Address == 0) - { - bI2C_Tx_cnts++; - if(bI2C_Tx_cnts < bI2C_TxFIFO_cnts) - SN_I2C0->TXDATA = *bTX_ptr++; - else if(bI2C_Tx_cnts == bI2C_TxFIFO_cnts) - Busy = 0; - } - else - Busy = 0; - } - break; - - /* SLA+W or Data has been transmitted and NACK has been received */ - case (NACK_DONE | mskI2C_MST_MASTER): - SN_I2C0->CTRL_b.STO = 1; - Error = 1; - break; - - /* START has been transmitted and prepare SLA+W/SLA+R */ - case (START_DONE | mskI2C_MST_MASTER): - #if (EEPROM_less_than_32K == 1) - SN_I2C0->TXDATA = Device_ADDRESS | (EEPROM_ADR_H << 1) | EEPROM_WR; - #else - SN_I2C0->TXDATA = Device_ADDRESS | EEPROM_WR; - #endif - break; - - default: - SN_I2C0->CTRL_b.I2CEN = 0; - SN_I2C0->CTRL_b.I2CEN = 1; - SN_I2C0->CTRL_b.STA = 1; - break; - } - } -} - diff --git a/os/hal/ports/SN32/LLD/SN32F2xx/I2C/I2C.h b/os/hal/ports/SN32/LLD/SN32F2xx/I2C/I2C.h deleted file mode 100644 index 7835a05b2c..0000000000 --- a/os/hal/ports/SN32/LLD/SN32F2xx/I2C/I2C.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef __SN32F2XX_I2C_H -#define __SN32F2XX_I2C_H - -/*_____ I N C L U D E S ____________________________________________________*/ -#include - -/*_____ D E F I N I T I O N S ______________________________________________*/ -#define EEPROM_less_than_32K 1 // 1: for EEPROM size less than 32K bits (4096x8) - // 0: for EEPROM size more than or equal to 32K bits (4096x8) - -#define Device_ADDRESS 0xA0 -#define Lost_Arbitration 0x100 -#define SLAVE_ADDRESS_HIT_TX 0x80 -#define SLAVE_ADDRESS_HIT_RX 0x40 -#define START_DONE 0x10 -#define STOP_DONE 0x08 -#define NACK_DONE 0x04 -#define ACK_DONE 0x02 -#define RX_DONE 0x01 - -/* I2C n SCL High Time register <(I2Cn_SCLHT> (0x20) */ -#define I2C0_SCLHT 14 //[7:0], Count for SCL High Period time - //SCL High Period Time = (SCLH+1) * I2C0_PCLK cycle -#define I2C0_SCLLT 14 //[7:0], Count for SCL Low Period time - //SCL Loq Period Time = (SCLL+1) * I2C0_PCLK cycle - - -/* I2C n Status register (0x04) */ - //[0:0]RX done status -#define I2C_RX_DN_NO_HANDSHAKE 0 //No RX with ACK/NACK transfer -#define I2C_RX_DN_HANDSHAKE 1 //8-bit RX with ACK/NACK transfer is done -#define mskI2C_RX_DN_NO_HANDSHAKE (I2C_RX_DN_NO_HANDSHAKE<<0) -#define mskI2C_RX_DN_HANDSHAKE (I2C_RX_DN_HANDSHAKE<<0) - - //[1:1]ACK done status -#define I2C_ACK_STAT_NO_RECEIVED_ACK 0 //Not received an ACK -#define I2C_ACK_STAT_RECEIVED_ACK 1 //Received an ACK -#define mskI2C_ACK_STAT_NO_RECEIVED_ACK (I2C_ACK_STAT_NO_RECEIVED_ACK<<1) -#define mskI2C_ACK_STAT_RECEIVED_ACK (I2C_ACK_STAT_RECEIVED_ACK<<1) - - - //[2:2]NACK done status -#define I2C_NACK_STAT_NO_RECEIVED_NACK 0 //Not received a NACK -#define I2C_NACK_STAT_RECEIVED_NACK 1 //Received a NACK -#define mskI2C_NACK_STAT_NO_RECEIVED_NACK (I2C_NACK_STAT_NO_RECEIVED_NACK<<2) -#define mskI2C_NACK_STAT_RECEIVED_NACK (I2C_NACK_STAT_RECEIVED_NACK<<2) - - //[3:3]Stop done status -#define I2C_STOP_DN_NO_STOP 0 //No STOP bit -#define I2C_STOP_DN_STOP 1 //MASTER mode, a STOP condition was issued - //SLAVE mode, a STOP condition was received -#define mskI2C_STOP_DN_NO_STOP (I2C_STOP_DN_NO_STOP<<3) -#define mskI2C_STOP_DN_STOP (I2C_STOP_DN_STOP<<3) - - //[4:4]Start done status -#define I2C_START_DN_NO_START 0 //No START bit -#define I2C_START_DN_START 1 //MASTER mode, a START bit was issued - //SLAVE mode, a START bit was received -#define mskI2C_START_DN_NO_START (I2C_START_DN_NO_START<<4) -#define mskI2C_START_DN_START (I2C_START_DN_START<<4) - - -#define I2C_MST_SLAVE 0 //[5:5]Master/Slave status -#define I2C_MST_MASTER 1 -#define mskI2C_MST_SLAVE (I2C_MST_SLAVE<<5) -#define mskI2C_MST_MASTER (I2C_MST_MASTER<<5) - -#define mskI2C_STA_STA_STO ((I2C_START_DN_START<<4)|(I2C_STOP_DN_STOP<<3)) -#define mskI2C_STA_MASTER_STA_STO ((I2C_MST_MASTER<<5)|(I2C_START_DN_START<<4)|(I2C_STOP_DN_STOP<<3)) - - - //[6:6]Slave address check -#define I2C_SLV_RX_NO_MATCH_ADDR 0 //No matched slave address -#define I2C_SLV_RX_MATCH_ADDR 1 //Slave address hit, and is called for RX in slave mode -#define mskI2C_SLV_RX_NO_MATCH_ADDR (I2C_SLV_RX_NO_MATCH_ADDR<<6) -#define mskI2C_SLV_RX_MATCH_ADDR (I2C_SLV_RX_MATCH_ADDR<<6) - - //[7:7]Slave address check -#define I2C_SLV_TX_NO_MATCH_ADDR 0 //No matched slave address -#define I2C_SLV_TX_MATCH_ADDR 1 //Slave address hit, and is called for TX in slave mode. -#define mskI2C_SLV_TX_NO_MATCH_ADDR (I2C_SLV_TX_NO_MATCH_ADDR<<7) -#define mskI2C_SLV_TX_MATCH_ADDR (I2C_SLV_TX_MATCH_ADDR<<7) - - //[8:8]Lost arbitration -#define I2C_LOST_ARB_NO_LOST 0 //Not lost arbitration -#define I2C_LOST_ARB_LOST_ARBITRATION 1 //Lost arbitration -#define mskI2C_LOST_ARB_NO_LOST (I2C_LOST_ARB_NO_LOST<<8) -#define mskI2C_LOST_ARB_LOST_ARBITRATION (I2C_LOST_ARB_LOST_ARBITRATION<<8) - - //[9:9]Time-out status -#define I2C_TIMEOUT_NO_TIMEOUT 0 //No Timeout -#define I2C_TIMEOUT_TIMEOUT 1 //Timeout -#define mskI2C_TIMEOUT_TIMEOUT (I2C_TIMEOUT_TIMEOUT<<9) -#define mskI2C_TIMEOUT_NO_TIMEOUT (I2C_TIMEOUT_NO_TIMEOUT<<9) - - //[15:15]I2C Interrupt flag -#define I2C_I2CIF_STAUS_NO_CHANGE 0 //I2C status doesn’t change -#define I2C_I2CIF_INTERRUPT 1 //Read, I2C status changes - //Write, Clear this flag -#define mskI2C_I2CIF_STAUS_NO_CHANGE (I2C_I2CIF_STAUS_NO_CHANGE<<15) -#define mskI2C_I2CIF_INTERRUPT (I2C_I2CIF_INTERRUPT<<15) - - -//Recv FIFO -#define I2C_RX_FIFO_LENGTH 32 - -//TX FIFO -#define I2C_TX_FIFO_LENGTH 32 - -/*_____ M A C R O S ________________________________________________________*/ - - -/*_____ D E C L A R A T I O N S ____________________________________________*/ - -void I2C_Init(void); -void I2C_Start(void); -void I2C_Stop(void); -uint8_t I2C_Read(uint16_t eeprom_adr, uint8_t read_num); -uint8_t I2C_Write(uint16_t eeprom_adr, uint8_t write_num); -#endif /*__SN32F2XX_I2C_H*/ diff --git a/os/hal/ports/SN32/LLD/SN32F2xx/I2C/driver.mk b/os/hal/ports/SN32/LLD/SN32F2xx/I2C/driver.mk new file mode 100644 index 0000000000..7864517f37 --- /dev/null +++ b/os/hal/ports/SN32/LLD/SN32F2xx/I2C/driver.mk @@ -0,0 +1,21 @@ +ifeq ($(USE_HAL_I2C_FALLBACK),yes) + # Fallback SW driver. + ifeq ($(USE_SMART_BUILD),yes) + ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) + PLATFORMSRC_CONTRIB += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c + endif + else + PLATFORMSRC_CONTRIB += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c + endif + PLATFORMINC_CONTRIB += $(CHIBIOS)/os/hal/lib/fallback/I2C +else + # Default HW driver. + ifeq ($(USE_SMART_BUILD),yes) + ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) + PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/I2C/hal_i2c_lld.c + endif + else + PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/I2C/hal_i2c_lld.c + endif + PLATFORMINC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/I2C +endif diff --git a/os/hal/ports/SN32/LLD/SN32F2xx/I2C/hal_i2c_lld.c b/os/hal/ports/SN32/LLD/SN32F2xx/I2C/hal_i2c_lld.c new file mode 100644 index 0000000000..197ba3b285 --- /dev/null +++ b/os/hal/ports/SN32/LLD/SN32F2xx/I2C/hal_i2c_lld.c @@ -0,0 +1,406 @@ +/* + Copyright (C) 2023 1Conan + Copyright (C) 2023 Dimitris Mantzouranis + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file hal_i2c_lld.c + * @brief SN32 I2C subsystem low level driver source. + * + * @addtogroup I2C + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief I2C0 driver identifier. + */ +#if (SN32_I2C_USE_I2C0 == TRUE) || defined(__DOXYGEN__) +I2CDriver I2CD0; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static inline void i2c_lld_configure(I2CDriver *i2cp) { + i2cp->i2c->SCLHT = i2cp->config->high_time; + i2cp->i2c->SCLLT = i2cp->config->low_time; + i2cp->i2c->TOCTRL = i2cp->config->timeout; + i2cp->i2c->CTRL_b.I2CEN = true; +} + +static inline void i2c_lld_irq_handler(I2CDriver * i2cp) { + chSysLockFromISR(); + i2cp -> i2c -> STAT_b.I2CIF = true; + chSysUnlockFromISR(); + + if (i2cp -> i2c -> STAT_b.LOST_ARB) { + i2cp -> state = I2C_ARBITRATION_LOST; + _i2c_wakeup_error_isr(i2cp); + return; + } + if (i2cp -> i2c -> STAT_b.NACK_STAT) { + i2cp -> i2c -> CTRL_b.ACK = true; + } else { + if (i2cp -> i2c -> STAT_b.RX_DN && i2cp -> rx_buffer && i2cp -> count < i2cp -> rx_len) { + i2cp -> rx_buffer[i2cp -> count++] = i2cp -> i2c -> RXDATA; + i2cp -> i2c -> CTRL_b.ACK = true; + return; + } else { + if (i2cp -> i2c -> STAT_b.SLV_RX_HIT) { + i2cp -> i2c -> CTRL_b.ACK = true; + return; + } + if (i2cp -> i2c -> STAT_b.SLV_TX_HIT) { + //silent return + return; + } + } + if (i2cp -> i2c -> STAT_b.ACK_STAT && i2cp -> tx_buffer && i2cp -> count < i2cp -> tx_len) { + i2cp -> i2c -> TXDATA = i2cp -> tx_buffer[i2cp -> count++]; + return; + } + } + + if ((i2cp -> rx_buffer && !i2cp -> tx_buffer) || (!i2cp -> rx_buffer && i2cp -> tx_buffer)) { + if ((i2cp -> count == i2cp -> rx_len) || (i2cp -> count == i2cp -> tx_len)) { + i2cp -> i2c -> CTRL_b.STO = true; + i2cp -> i2c -> CTRL_b.I2CEN = false; + i2cp -> i2c -> CTRL_b.I2CEN = true; + i2cp -> state = I2C_STOP; + _i2c_wakeup_isr(i2cp); + return; + } + } +} +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if SN32_I2C_USE_I2C0 +OSAL_IRQ_HANDLER(SN32_I2C0_GLOBAL_HANDLER) { + OSAL_IRQ_PROLOGUE(); + + i2c_lld_irq_handler(&I2CD0); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level I2C driver initialization. + * + * @notapi + */ +void i2c_lld_init(void) { + +#if SN32_I2C_USE_I2C0 == TRUE + i2cObjectInit(&I2CD0); + I2CD0.thread = NULL; + I2CD0.i2c = SN32_I2C0; +#endif +} + +/** + * @brief Configures and activates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_start(I2CDriver *i2cp) { + + if (i2cp->state == I2C_STOP) { + /* Enables the peripheral.*/ +#if SN32_I2C_USE_I2C0 == TRUE + if (&I2CD0 == i2cp) { + sys1EnableI2C0(); + nvicClearPending(SN32_I2C0_GLOBAL_NUMBER); + nvicEnableVector(SN32_I2C0_GLOBAL_NUMBER, SN32_I2C_I2C0_IRQ_PRIORITY); + } +#endif + } + + i2c_lld_configure(i2cp); +} + +/** + * @brief Deactivates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_stop(I2CDriver *i2cp) { + + if (i2cp->state != I2C_STOP) { + + i2cp->i2c->CTRL_b.I2CEN = false; + + /* Disables the peripheral.*/ +#if SN32_I2C_USE_I2C0 == TRUE + if (&I2CD0 == i2cp) { + sys1DisableI2C0(); + nvicDisableVector(SN32_I2C0_GLOBAL_NUMBER); + } +#endif + } +} + +/** + * @brief Receives data via the I2C bus as master. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout) { + + systime_t start, end; + + /* Resetting error flags for this transfer.*/ + i2cp->errors = I2C_NO_ERROR; + + /* Initializes driver fields, LSB = 1 -> receive.*/ + i2cp->addr = (addr << 1) | 0x01; + + /* Releases the lock from high level driver.*/ + osalSysUnlock(); + + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, OSAL_MS2I(SN32_I2C_BUSY_TIMEOUT)); + + /* Waits for a timeout condition.*/ + while (true) { + osalSysLock(); + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) + return MSG_TIMEOUT; + + osalSysUnlock(); + } + i2cp->rx_buffer = rxbuf; + i2cp->rx_len = rxbytes; + i2cp->count = 0; + i2cp->i2c->CTRL_b.STA = true; + i2cp->i2c->TXDATA = addr; + + /* Waits for the operation completion or a timeout.*/ + return osalThreadSuspendTimeoutS(&i2cp->thread, timeout); + +} + +/** + * @brief Transmits data via the I2C bus as master. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[in] txbuf pointer to the transmit buffer + * @param[in] txbytes number of bytes to be transmitted + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout) { + + systime_t start, end; + + /* Resetting error flags for this transfer.*/ + i2cp->errors = I2C_NO_ERROR; + + /* Initializes driver fields, LSB = 0 -> transmit.*/ + i2cp->addr = (addr << 1); + + /* Releases the lock from high level driver.*/ + osalSysUnlock(); + + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, OSAL_MS2I(SN32_I2C_BUSY_TIMEOUT)); + + /* Waits for a timeout condition.*/ + while (true) { + osalSysLock(); + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) + return MSG_TIMEOUT; + + osalSysUnlock(); + } + i2cp->tx_buffer = txbuf; + i2cp->tx_len = txbytes; + i2cp->count = 0; + i2cp->i2c->CTRL_b.STA = true; + i2cp->i2c->TXDATA = addr; + + /* Waits for the operation completion or a timeout.*/ + return osalThreadSuspendTimeoutS(&i2cp->thread, timeout); +} + +#if (I2C_SUPPORTS_SLAVE_MODE == TRUE) || defined(__DOXYGEN__) +/** + * @brief Listen I2C bus for address match. + * @details Use 7 bit address (10 bit,dual and general call address dosn't implement yet) . + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * + * @notapi + */ +msg_t i2c_lld_match_address(I2CDriver *i2cp, i2caddr_t addr) { + + uint16_t i2cadr = addr << 1; + uint16_t ownAdr = i2cp->i2c->SLVADRR0 & (0x7f<<1); + + if (ownAdr == 0 || ownAdr == i2cadr) + i2cp->i2c->SLVADRR0 = i2cadr; + else + /* cannot add this address to set of those matched */ + return MSG_RESET; + + return MSG_OK; + +} + +/** + * @brief Receive data via the I2C bus as slave and call handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes size of receive buffer + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @api + */ +msg_t i2c_lld_slave_receive_timeout(I2CDriver *i2cp, + uint8_t *rxbuf, + size_t rxbytes, + sysinterval_t timeout) { + i2cp->rx_buffer = rxbuf; + i2cp->rx_len = rxbytes; + i2cp->count = 0; + + /* Waits for the operation completion or a timeout.*/ + return osalThreadSuspendTimeoutS(&i2cp->thread, timeout); +} + +/** + * @brief Transmits data via the I2C bus as slave. + * @details Call this function when Master request data (in request handler) + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] txbuf pointer to the transmit buffer + * @param[in] txbytes number of bytes to be transmitted + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @api + */ +msg_t i2c_lld_slave_transmit_timeout(I2CDriver *i2cp, + const uint8_t *txbuf, + size_t txbytes, + sysinterval_t timeout) { + i2cp->tx_buffer = txbuf; + i2cp->tx_len = txbytes; + i2cp->count = 0; + + /* Waits for the operation completion or a timeout.*/ + return osalThreadSuspendTimeoutS(&i2cp->thread, timeout); +} +#endif /* I2C_SUPPORTS_SLAVE_MODE == TRUE */ +#endif /* HAL_USE_I2C == TRUE */ + +/** @} */ + + diff --git a/os/hal/ports/SN32/LLD/SN32F2xx/I2C/hal_i2c_lld.h b/os/hal/ports/SN32/LLD/SN32F2xx/I2C/hal_i2c_lld.h new file mode 100644 index 0000000000..4c700e5b51 --- /dev/null +++ b/os/hal/ports/SN32/LLD/SN32F2xx/I2C/hal_i2c_lld.h @@ -0,0 +1,229 @@ +/* + Copyright (C) 2023 1Conan + Copyright (C) 2023 Dimitris Mantzouranis + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file hal_i2c_lld.h + * @brief SN32 I2C subsystem low level driver header. + * + * @addtogroup I2C + * @{ + */ + +#ifndef HAL_I2C_LLD_H +#define HAL_I2C_LLD_H + +#if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ +#include "sn32_i2c.h" +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name SN32 configuration options + * @{ + */ +/** + * @brief I2C0 driver enable switch. + * @details If set to @p TRUE the support for I2C0 is included. + * @note The default is @p FALSE. + */ +#if !defined(SN32_I2C_USE_I2C0) || defined(__DOXYGEN__) +#define SN32_I2C_USE_I2C0 FALSE +#endif + +/** + * @brief I2C0 interrupt priority level setting. + */ +#if !defined(SN32_I2C_I2C0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define SN32_I2C_I2C0_IRQ_PRIORITY 3 +#endif + +/** + * @brief I2C timeout on busy condition in milliseconds. + */ +#if !defined(SN32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__) +#define SN32_I2C_BUSY_TIMEOUT 50 +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +#if SN32_HAS_I2C0 +#define SN32_I2C0_BASE SN_I2C0_BASE +#define SN32_I2C0 ((sn32_i2c_t *)SN_I2C0_BASE) +#endif + +/** + * @brief Type representing an I2C address. + */ +typedef uint16_t i2caddr_t; + +/** + * @brief Type of I2C Driver condition flags. + */ +typedef uint32_t i2cflags_t; + +/** + * @brief I2C driver configuration structure. + * @note Implementations may extend this structure to contain more, + * architecture dependent, fields. + */ +struct hal_i2c_config { + /* End of the mandatory fields.*/ + uint8_t high_time; + uint8_t low_time; + uint16_t timeout; +}; + +/** + * @brief Type of a structure representing an I2C configuration. + */ +typedef struct hal_i2c_config I2CConfig; + +/** + * @brief Type of a structure representing an I2C driver. + */ +typedef struct hal_i2c_driver I2CDriver; + +/** + * @brief Structure representing an I2C driver. + */ +struct hal_i2c_driver { + /** + * @brief Driver state. + */ + i2cstate_t state; + /** + * @brief Current configuration data. + */ + const I2CConfig *config; + /** + * @brief Error flags. + */ + i2cflags_t errors; +#if (I2C_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) + mutex_t mutex; +#endif +#if defined(I2C_DRIVER_EXT_FIELDS) + I2C_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + + /* @brief Thread waiting for I/O completion. */ + thread_reference_t thread; + /* @brief Current slave address without R/W bit. */ + i2caddr_t addr; + + sn32_i2c_t *i2c; + /* @brief Pointer to the buffer to put received data. */ + uint8_t *rx_buffer; + /* @brief Number of bytes of data to receive. */ + size_t rx_len; + /* @brief Pointer to the buffer with data to send. */ + const uint8_t *tx_buffer; + /* @brief Number of bytes of data to send. */ + size_t tx_len; + /* @brief Current count of transmitted data. */ + size_t count; +}; + +/* For compatibility, some LLDs could not export this.*/ +#if !defined(I2C_SUPPORTS_SLAVE_MODE) +#define I2C_SUPPORTS_SLAVE_MODE TRUE +#endif + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Get errors from I2C driver. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define i2c_lld_get_errors(i2cp) ((i2cp)->errors) +/** + * @brief Get rx length from I2C driver. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define i2c_lld_get_rxbytes(i2cp) (i2cp)->rx_len +/** + * @brief Get tx length from I2C driver. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define i2c_lld_get_txbytes(i2cp) (i2cp)->tx_len + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (SN32_I2C_USE_I2C0 == TRUE) && !defined(__DOXYGEN__) +extern I2CDriver I2CD0; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void i2c_lld_init(void); + void i2c_lld_start(I2CDriver *i2cp); + void i2c_lld_stop(I2CDriver *i2cp); + msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout); + msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout); +#if (I2C_SUPPORTS_SLAVE_MODE == TRUE) || defined(__DOXYGEN__) + msg_t i2c_lld_match_address(I2CDriver *i2cp, i2caddr_t addr); + msg_t i2c_lld_slave_receive_timeout(I2CDriver *i2cp, + uint8_t *rxbuf, + size_t rxbytes, + sysinterval_t timeout); + msg_t i2c_lld_slave_transmit_timeout(I2CDriver *i2cp, + const uint8_t *txbuf, + size_t txbytes, + sysinterval_t timeout); +#endif /* I2C_SUPPORTS_SLAVE_MODE == TRUE */ +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_I2C == TRUE */ + +#endif /* HAL_I2C_LLD_H */ + +/** @} */ \ No newline at end of file diff --git a/os/hal/ports/SN32/LLD/SN32F2xx/I2C/sn32_i2c.h b/os/hal/ports/SN32/LLD/SN32F2xx/I2C/sn32_i2c.h new file mode 100644 index 0000000000..9301d77bbd --- /dev/null +++ b/os/hal/ports/SN32/LLD/SN32F2xx/I2C/sn32_i2c.h @@ -0,0 +1,85 @@ +/* + Copyright (C) 2023 1Conan + Copyright (C) 2023 Dimitris Mantzouranis + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef SN32_I2C_H +#define SN32_I2C_H + +typedef struct { + union { + uint32_t CTRL; + + struct { + uint32_t : 1; + uint32_t NACK : 1; + uint32_t ACK : 1; + uint32_t : 1; + uint32_t STO : 1; + uint32_t STA : 1; + uint32_t : 1; + uint32_t MODE : 1; + uint32_t I2CEN : 1; + uint32_t : 23; + } CTRL_b; + }; + + union { + uint32_t STAT; + + struct { + uint32_t RX_DN : 1; + uint32_t ACK_STAT : 1; + uint32_t NACK_STAT : 1; + uint32_t STOP_DN : 1; + uint32_t START_DN : 1; + uint32_t MST : 1; + uint32_t SLV_RX_HIT : 1; + uint32_t SLV_TX_HIT : 1; + uint32_t LOST_ARB : 1; + uint32_t TIMEOUT : 1; + uint32_t : 5; + uint32_t I2CIF : 1; + uint32_t : 16; + } STAT_b; + }; + + uint32_t TXDATA; + uint32_t RXDATA; + + union { + uint32_t SLVADRR0; + + struct { + uint32_t ADDR : 10; + uint32_t : 20; + uint32_t GCEN : 1; + uint32_t ADD_MODE : 1; + + } SLVADDR0_b; + }; + + uint32_t SLVADDR1; + uint32_t SLVADDR2; + uint32_t SLVADDR3; + uint32_t SCLHT; + uint32_t SCLLT; + uint32_t SCLCT; + uint32_t TOCTRL; +} sn32_i2c_t; + +#endif /* SN32_I2C_H */ + +/** @} */ \ No newline at end of file diff --git a/os/hal/ports/SN32/SN32F240B/platform.mk b/os/hal/ports/SN32/SN32F240B/platform.mk index 66b64149d0..309a76ac34 100644 --- a/os/hal/ports/SN32/SN32F240B/platform.mk +++ b/os/hal/ports/SN32/SN32F240B/platform.mk @@ -25,6 +25,7 @@ include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/CT/driver.mk include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/FLASH/driver.mk include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/SysTick/driver.mk include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/SPI/driver.mk +include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/I2C/driver.mk include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/WDT/driver.mk # Shared variables diff --git a/os/hal/ports/SN32/SN32F260/platform.mk b/os/hal/ports/SN32/SN32F260/platform.mk index 2082c73908..e6ee0bd0f4 100644 --- a/os/hal/ports/SN32/SN32F260/platform.mk +++ b/os/hal/ports/SN32/SN32F260/platform.mk @@ -25,6 +25,7 @@ include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/CT/driver.mk include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/FLASH/driver.mk include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/SysTick/driver.mk include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/SPI/driver.mk +include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/I2C/driver.mk include ${CHIBIOS_CONTRIB}/os/hal/ports/SN32/LLD/SN32F2xx/WDT/driver.mk # Shared variables