/* * Copyright (C) 2013 Uwe Bonnes(bon@elektron.ikp.physik.tu-darmstadt.de * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ */ /*! * \file arch/cm3/dev/stm/stm32_i2cbus_v1.c * \brief I2C bus driver for I2C hardware in STM32F1/2/4 and STM32L1. * * It doesn't consider Slave operation yet * * It is intended that this driver replaces the current STM TWI driver, * which doesn't allow to have different types of busses in a single * application, for example TWI hardware and bit banging interfaces. * This new I2C driver layout allows to attach any I2C slave driver to * any I2C bus driver by calling NutRegisterI2cSlave(). * * \verbatim * $Id: stm32_i2cbus_v1.c 5623 2014-04-02 16:26:30Z u_bonnes $ * \endverbatim */ /*! * \brief I2C bus driver for STM32F1/2/4 and L1 hardware. * * This is an interrupt driver, which supports master mode only. * Most error handling */ #include #include #include #include #include #include #include #include #include #include #include #include /*! * \addtogroup xgI2cBusSTM32 */ /*@{*/ /*! * \brief Local data of the STM32 I2C bus driver. */ typedef struct _STM32_I2CCB { /*! \brief Register base. */ uptr_t icb_base; /*! \brief SDA_PIN. */ uint32_t sda_pin; /*! \brief SCL_PIN. */ uint32_t scl_pin; /*! \brief SMBA_PIN. */ uint32_t smba_pin; /*! \brief System event handler. */ IRQ_HANDLER *icb_sig_ev; /*! \brief System error handler. */ IRQ_HANDLER *icb_sig_er; /*! \brief I2C message. */ NUTI2C_MSG *icb_msg; /*! \brief Thread waiting for completion. */ HANDLE icb_queue; /*! \brief Current Slave/ */ NUTI2C_SLAVE *slave; uint32_t errors; } STM32_I2CCB; /* * STM32V1 I2C Event interrupt function. */ static void I2cEventBusIrqHandler(void *arg) { STM32_I2CCB *icb = (STM32_I2CCB *) arg; NUTI2C_MSG *msg = icb->icb_msg; I2C_TypeDef *I2Cx = (I2C_TypeDef *) icb->icb_base; if(I2Cx->SR1 & I2C_SR1_SB) { /* Receiver EV5 */ if(msg->msg_widx >= msg->msg_wlen) { /* All bytes written, (re)start reading */ I2Cx->DR = icb->slave->slave_address<<1|1; } else I2Cx->DR = icb->slave->slave_address<<1; } if(I2Cx->SR1 & I2C_SR1_ADDR) { if (I2Cx->SR2 & I2C_SR2_TRA) { /* Transmitting*/ if (msg->msg_widx < msg->msg_wlen) { I2Cx->DR = msg->msg_wdat[msg->msg_widx]; msg->msg_widx++; } } else { /* Inhibit IRQ storm as TXE not cleared as we * have nothing written to DR Register */ I2Cx->CR2 |= I2C_CR2_ITBUFEN; if (msg->msg_rsiz >1) /* Receiver EV6*/ I2Cx->CR1 |= I2C_CR1_ACK; else { /* EV6_1*/ I2Cx->CR1 &= ~I2C_CR1_ACK; I2Cx->CR1 |= I2C_CR1_STOP; } } } if (I2Cx->SR1 & I2C_SR1_TXE) { if (msg->msg_widx < msg->msg_wlen) { I2Cx->DR = msg->msg_wdat[msg->msg_widx]; msg->msg_widx++; } else { I2Cx->CR2 &= ~I2C_CR2_ITBUFEN; if (msg->msg_rsiz) I2Cx->CR1 |= I2C_CR1_START; else I2Cx->CR1 |= I2C_CR1_STOP; } } if (I2Cx->SR1 & I2C_SR1_RXNE) { /* Receiver EV7*/ msg->msg_rdat[msg->msg_ridx]= I2Cx->DR; msg->msg_ridx++; if(msg->msg_ridx + 2 > msg->msg_rsiz) { I2Cx->CR1 &= ~I2C_CR1_ACK; I2Cx->CR1 |= I2C_CR1_STOP; } if (msg->msg_ridx + 1 > msg->msg_rsiz) { NutEventPostFromIrq(&icb->icb_queue); } } if (I2Cx->SR1 & I2C_SR1_BTF) { /* Terminate write transaction without read*/ if ((I2Cx->SR2 & I2C_SR2_TRA) && !(msg->msg_rsiz)) { I2Cx->CR2 &= ~(I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); NutEventPostFromIrq(&icb->icb_queue); } } } /* * STM32V1 I2C Error interrupt function. */ static void I2cErrorBusIrqHandler(void *arg) { STM32_I2CCB *icb = (STM32_I2CCB *) arg; I2C_TypeDef *I2Cx = (I2C_TypeDef *) icb->icb_base; icb->errors = I2Cx->SR1; I2Cx->SR1 &= ~(I2C_SR1_SMBALERT|I2C_SR1_TIMEOUT|I2C_SR1_PECERR|I2C_SR1_OVR| I2C_SR1_AF|I2C_SR1_ARLO|I2C_SR1_BERR); NutEventPostFromIrq(&icb->icb_queue); } /*! * \brief I2C bus transfer (STM I2C implementation). * * This function is called by the platform independent code via the * NUTI2C_BUS::bus_tran function pointer. */ static int I2cBusTran(NUTI2C_SLAVE *slave, NUTI2C_MSG *msg) { NUTI2C_BUS *bus; STM32_I2CCB *icb; I2C_TypeDef *I2Cx; int rc; bus = slave->slave_bus; NUTASSERT(bus != NULL); NUTASSERT(bus->bus_icb != NULL); icb = (STM32_I2CCB *) bus->bus_icb; icb->icb_msg = msg; I2Cx = (I2C_TypeDef *) icb->icb_base; msg->msg_widx = 0; msg->msg_ridx = 0; icb->slave = slave; icb->errors = 0; /* Enable Interrupts */ I2Cx->CR2 |= I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN |I2C_CR2_ITERREN; I2Cx->CR1 |= I2C_CR1_START; rc = NutEventWait(&icb->icb_queue, slave->slave_timeout); I2Cx->CR2 &= ~I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN |I2C_CR2_ITERREN; if(icb->errors) { I2Cx->CR1 |= I2C_CR1_STOP; msg->msg_ridx = -1; } if(rc) msg->msg_ridx = -1; return msg->msg_ridx; } static int checkpin_and_config(STM32_I2CCB *icb) { uint32_t sda_port, scl_port; if (icb->icb_base == I2C1_BASE) { sda_port= NUTGPIO_PORTB; scl_port= NUTGPIO_PORTB; #if defined (GPIO_AF_I2C1) if ((icb->sda_pin != 7) && (icb->sda_pin != 9)) return -1; if ((icb->scl_pin != 6) && (icb->scl_pin != 8)) return -1; if ((icb->smba_pin != 5) && (icb->smba_pin != -1)) return -1; GpioPinConfigSet( sda_port, icb->sda_pin, GPIO_CFG_OUTPUT| GPIO_CFG_PERIPHAL| GPIO_CFG_MULTIDRIVE| GPIO_CFG_PULLUP | GPIO_CFG_SPEED_FAST); GpioPinConfigSet( scl_port ,icb->scl_pin, GPIO_CFG_OUTPUT| GPIO_CFG_PERIPHAL| GPIO_CFG_MULTIDRIVE| GPIO_CFG_PULLUP | GPIO_CFG_SPEED_FAST); GPIO_PinAFConfig((GPIO_TypeDef*) sda_port, icb->sda_pin, GPIO_AF_I2C1); GPIO_PinAFConfig((GPIO_TypeDef*) scl_port, icb->scl_pin, GPIO_AF_I2C1); #else if ((icb->sda_pin == 7) && (icb->scl_pin == 6)) AFIO->MAPR &= ~AFIO_MAPR_I2C1_REMAP; else if ((icb->sda_pin == 9) && (icb->scl_pin == 8)) AFIO->MAPR |= AFIO_MAPR_I2C1_REMAP; else return -1; GpioPinConfigSet( sda_port, icb->sda_pin, GPIO_CFG_OUTPUT| GPIO_CFG_PERIPHAL| GPIO_CFG_MULTIDRIVE| GPIO_CFG_PULLUP | GPIO_CFG_SPEED_FAST); GpioPinConfigSet( scl_port ,icb->scl_pin, GPIO_CFG_OUTPUT| GPIO_CFG_PERIPHAL| GPIO_CFG_MULTIDRIVE| GPIO_CFG_PULLUP | GPIO_CFG_SPEED_FAST); #endif if (icb->smba_pin == 5) { /* TODO: How should SMBA pin be set?*/ GpioPinConfigSet( NUTGPIO_PORTA, icb->scl_pin, GPIO_CFG_OUTPUT| GPIO_CFG_PERIPHAL| GPIO_CFG_MULTIDRIVE| GPIO_CFG_PULLUP | GPIO_CFG_SPEED_FAST); #if defined(GPIO_AF_I2C1) GPIO_PinAFConfig(GPIOA, icb->smba_pin, GPIO_AF_I2C1); #endif } RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST; RCC->APB1RSTR &= ~RCC_APB1RSTR_I2C1RST; } else if (icb->icb_base == I2C2_BASE) { #if defined(GPIO_AF_I2C1) if ((icb->sda_pin != 0) && (icb->sda_pin != 5)&& (icb->sda_pin != 11)) return -1; if ((icb->scl_pin != 1) && (icb->scl_pin != 4) && (icb->sda_pin != 10)) return -1; if ((icb->smba_pin != 12) && (icb->smba_pin != 2) && (icb->smba_pin != 6) && (icb->smba_pin != -1)) return -1; if (icb->sda_pin == 11) sda_port= NUTGPIO_PORTB; #if defined(GPIOF_BASE) else if (icb->sda_pin == 0) sda_port= NUTGPIO_PORTF; #endif #if defined(GPIOH_BASE) else if (icb->sda_pin == 5) sda_port= NUTGPIO_PORTH; #endif else return -1; if (icb->scl_pin == 10) scl_port= NUTGPIO_PORTB; #if defined(GPIOF_BASE) else if (icb->scl_pin == 1) scl_port= NUTGPIO_PORTF; #endif #if defined(GPIOH_BASE) else if (icb->scl_pin == 4) scl_port= NUTGPIO_PORTH; #endif else return -1; if (icb->smba_pin == 12) scl_port= NUTGPIO_PORTB; #if defined(GPIOF_BASE) else if (icb->smba_pin == 2) scl_port= NUTGPIO_PORTF; #endif #if defined(GPIOH_BASE) else if (icb->scl_pin == 4) scl_port= NUTGPIO_PORTH; #endif else return -1; if (icb->smba_pin == 12) scl_port= NUTGPIO_PORTB; #if defined(GPIOF_BASE) else if (icb->smba_pin == 2) scl_port= NUTGPIO_PORTF; #endif #if defined(GPIOH_BASE) else if (icb->smba_pin == 6) scl_port= NUTGPIO_PORTH; #endif /* Fixme: Handle SMBA Pin*/ GPIO_PinAFConfig((GPIO_TypeDef*) sda_port, icb->sda_pin, GPIO_AF_I2C1); GPIO_PinAFConfig((GPIO_TypeDef*) scl_port, icb->scl_pin, GPIO_AF_I2C1); #else if ((icb->sda_pin != 11) || (icb->scl_pin != 10)) return -1; if ((icb->smba_pin != -1) && (icb->smba_pin != 12)) return -1; sda_port= NUTGPIO_PORTB; scl_port= NUTGPIO_PORTB; #endif GpioPinConfigSet( sda_port, icb->sda_pin, GPIO_CFG_OUTPUT| GPIO_CFG_PERIPHAL| GPIO_CFG_MULTIDRIVE| GPIO_CFG_PULLUP | GPIO_CFG_SPEED_FAST); GpioPinConfigSet( scl_port ,icb->scl_pin, GPIO_CFG_OUTPUT| GPIO_CFG_PERIPHAL| GPIO_CFG_MULTIDRIVE| GPIO_CFG_PULLUP | GPIO_CFG_SPEED_FAST); if (icb->smba_pin == 12) { /* TODO: How should SMBA pin be set?*/ GpioPinConfigSet( NUTGPIO_PORTA, icb->scl_pin, GPIO_CFG_OUTPUT| GPIO_CFG_PERIPHAL| GPIO_CFG_MULTIDRIVE| GPIO_CFG_PULLUP | GPIO_CFG_SPEED_FAST); #if defined(GPIO_AF_I2C1) GPIO_PinAFConfig(GPIOA, icb->smba_pin, GPIO_AF_I2C1); #endif } RCC->APB1ENR |= RCC_APB1ENR_I2C2EN; RCC->APB1RSTR |= RCC_APB1RSTR_I2C2RST; RCC->APB1RSTR &= ~RCC_APB1RSTR_I2C2RST; } #if defined(I2C3_BASE) else if (icb->icb_base == I2C3_BASE) { #if defined(GPIO_AF_I2C1) if ((icb->sda_pin != 9) && (icb->sda_pin != 8)) return -1; if ((icb->scl_pin != 8) && (icb->scl_pin != 7)) return -1; if ((icb->smba_pin != 9) && (icb->smba_pin != 809) && (icb->smba_pin != -1)) return -1; if (icb->sda_pin == 9) sda_port= NUTGPIO_PORTC; else if (icb->sda_pin == 8) sda_port= NUTGPIO_PORTH; else return -1; if (icb->scl_pin == 8) scl_port= NUTGPIO_PORTA; else if (icb->scl_pin == 7) scl_port= NUTGPIO_PORTH; else return -1; if (icb->smba_pin == 9) scl_port= NUTGPIO_PORTA; else if (icb->smba_pin == 809) scl_port= NUTGPIO_PORTH; /* Fixme: Handle SMNa Pin*/ GPIO_PinAFConfig((GPIO_TypeDef*) sda_port, icb->sda_pin, GPIO_AF_I2C1); GPIO_PinAFConfig((GPIO_TypeDef*) scl_port, icb->scl_pin, GPIO_AF_I2C1); #else if ((icb->sda_pin != 11) || (icb->scl_pin != 10)) return -1; if ((icb->smba_pin != -1) || (icb->smba_pin != 12)) return -1; #endif GpioPinConfigSet( sda_port, icb->sda_pin, GPIO_CFG_OUTPUT| GPIO_CFG_PERIPHAL| GPIO_CFG_MULTIDRIVE| GPIO_CFG_PULLUP | GPIO_CFG_SPEED_FAST); GpioPinConfigSet( scl_port ,icb->scl_pin, GPIO_CFG_OUTPUT| GPIO_CFG_PERIPHAL| GPIO_CFG_MULTIDRIVE| GPIO_CFG_PULLUP | GPIO_CFG_SPEED_FAST); if (icb->smba_pin == 12) { /* TODO: How should SMBA pin be set?*/ GpioPinConfigSet( NUTGPIO_PORTA, icb->scl_pin, GPIO_CFG_OUTPUT| GPIO_CFG_PERIPHAL| GPIO_CFG_MULTIDRIVE| GPIO_CFG_PULLUP | GPIO_CFG_SPEED_FAST); #if defined(GPIO_AF_I2C1) GPIO_PinAFConfig(GPIOA, icb->smba_pin, GPIO_AF_I2C1); #endif } RCC->APB1ENR |= RCC_APB1ENR_I2C3EN; RCC->APB1RSTR |= RCC_APB1RSTR_I2C3RST; RCC->APB1RSTR &= ~RCC_APB1RSTR_I2C3RST; } #endif else return -1; return 0; } /*! * \brief Configure the I2C bus controller (STM32V1 I2C implementation). * * This function is called by the platform independent code via the * NUTI2C_BUS::bus_conf function pointer. Most implementations will * also call this function during initialization to set the * default configuration. * */ static int I2cBusConf(NUTI2C_BUS *bus) { STM32_I2CCB *icb; uint32_t speed; I2C_TypeDef *I2Cx; uint16_t ccr; uint32_t apbclk = NutClockGet(NUT_HWCLK_PCLK1); uint16_t frqrange = (uint16_t)(apbclk/1000000); uint16_t cr1; /* Check parameters. */ NUTASSERT(bus != NULL); NUTASSERT(bus->bus_icb != NULL); icb = (STM32_I2CCB *) bus->bus_icb; I2Cx = (I2C_TypeDef*) icb->icb_base; cr1 = I2Cx->CR1; /* Get requested speed or use the default. */ speed = bus->bus_rate; if (speed == 0) { speed = 100000L; } if (speed > 400000) { /* Speed out of range */ speed = 400000; } /* Configure speed in fast mode */ if( speed > 100000 ) { /* calculate CCR value */ ccr = (uint16_t)(apbclk/(speed*25)); if( ccr == 0 ) { /* keep minimum allowed value */ ccr = 0x0001; } /* Set DUTY bit and set F/S bit for fast mode */ ccr |= (I2C_CCR_DUTY|I2C_CCR_FS); /* Set Maximum Rise Time for fast mode */ I2Cx->TRISE = (uint16_t)(((frqrange*300)/1000)+1); } else { /* Standard mode speed calculate */ ccr = (uint16_t)(apbclk/(speed<<1)); /* Test if CCR value is under 0x4 */ if( ccr < 4 ) { /* Set minimum allowed value */ ccr = 4; } else if ( ccr > I2C_CCR_CCR ) { ccr = I2C_CCR_CCR; } /* Set Maximum Rise Time for standard mode */ I2Cx->TRISE = frqrange+1; } /* Write CCR register */ I2Cx->CCR = ccr; /* Restore the CR1 register */ I2Cx->CR1 = cr1; return 0; } /*! * \brief Initialize the I2C bus controller (STM32 implementation). * * This function is called by the platform independent code via the * NUTI2C_BUS::bus_init function pointer when the first slave is * attached to this bus. Note, that NUTI2C_BUS::bus_rate must be zero * initially. Otherwise no call to this function will take place. * * This function must do all required initializations so that the * driver will be ready to process transfers via NUTI2C_BUS::bus_tran. * * This function must return 0 on success or -1 otherwise. */ static int I2cBusInit(NUTI2C_BUS *bus) { I2C_TypeDef *I2Cx; STM32_I2CCB *icb; icb = (STM32_I2CCB *) bus->bus_icb; if (checkpin_and_config(icb)) return -1; /* Try to configure the bus*/ if (I2cBusConf(bus)) { return -1; } I2Cx = (I2C_TypeDef*) icb->icb_base; I2Cx->CR2 = I2C_CR2_FREQ; I2Cx->CR2 |= (NutClockGet(NUT_HWCLK_PCLK1)/1000000); I2Cx->CR1 |= I2C_CR1_PE; if (NutRegisterIrqHandler(icb->icb_sig_ev, I2cEventBusIrqHandler, icb)) return -1; if (NutRegisterIrqHandler(icb->icb_sig_er, I2cErrorBusIrqHandler, icb)) return -1; NutIrqEnable(icb->icb_sig_ev); NutIrqEnable(icb->icb_sig_er); return 0; } /*! * \brief Probe the I2C bus for a specified slave address * (STM32V1 implementation). * * This function is called by the platform independent code via the * NUTI2C_BUS::bus_probe function pointer. This may happen even if no * slave device had been attached to the bus and thus without any * previous call to NUTI2C_BUS::bus_init. However, in that case * NUTI2C_BUS::bus_configure will have been called. * * */ static int I2cBusProbe(NUTI2C_BUS *bus, int sla) { STM32_I2CCB *icb; I2C_TypeDef *I2Cx; uint32_t tmo; int res = -1; icb = (STM32_I2CCB *) bus->bus_icb; I2Cx = (I2C_TypeDef*) icb->icb_base; if ((I2Cx->CR1 & I2C_CR1_PE)== 0) { int res; res = I2cBusInit(bus); if (res) return res; } I2Cx->CR1 |= I2C_CR1_START; /* Wait until START has been sent*/ for(tmo = NutGetMillis(); NutGetMillis() - tmo < bus->bus_timeout;) { res = !(I2Cx->SR1 & I2C_SR1_SB); if (res == 0) break; } if (res) return -1; I2Cx->DR = sla<<1; /* Sequence Read SR1, write DR clears SB*/ /* Wait until Adress has been sent*/ for(; NutGetMillis() - tmo < bus->bus_timeout;) { res = I2Cx->SR1; if (res & I2C_SR1_ADDR) { (void)I2Cx->SR2; break; } if (res & I2C_SR1_AF) { I2Cx->SR1 &= ~I2C_SR1_AF; break; } } I2Cx->CR1 &= (uint16_t)~I2C_CR1_ACK; I2Cx->CR1 |= I2C_CR1_STOP; return (res & I2C_SR1_ADDR)?0:-1; } /* F10: I2C1 SDA PB7 PB9 I2C1_SCL PB6 PB8 I2C1_SMBA PB5 I2C2_SDA PB11 I2C2_SCL PB10 I2C2_SMBA PB12 F2/4: AF4/ L1: AFIO4 I2C1 SDA PB7 PB9 I2C1_SCL PB6 PB8 I2C1_SMBA PB5 I2C2_SDA PB11 PF0 PH5 I2C2_SCL PB10 PF1 PH4 I2C2_SMBA PB12 PF2 PH6 I2C3_SDA PC9 PH8 I2C3 SCL PA8 PH7 I2C3 SMBA PA9 PH9 */ static STM32_I2CCB i2c1cb = { I2C1_BASE, /* Register Base */ #if defined(MCU_STM32F1) #if defined(I2C1_REMAP) 7, /* SDA Default PB7*/ 6, /* SCL Default PB6*/ #else 9, /* SDA Remap PB9*/ 8, /* SCL Remap PB8*/ #endif #else #if defined (I2C1_SDA_PIN) I2C1_SDA_PIN, /* SDA Pin number */ #else -1, /* SDA Pin number */ #endif #if defined (I2C1_SCL_PIN) I2C1_SCL_PIN, /* SDA Pin number */ #else -1, /* SDA Pin number */ #endif #endif #if defined (I2C1_SMBA_PIN) I2C1_SMBA_PIN, /* SDA Pin number */ #else -1, /* SDA Pin number */ #endif &sig_TWI1_EV, /* Event signal */ &sig_TWI1_ER, /* Error signal */ NULL, /* icb_msg */ NULL /* icb_queue */ }; static STM32_I2CCB i2c2cb = { I2C2_BASE, /* Register Base */ #if defined(MCU_STM32F1) 11, /* SDA Pin number */ 10, /* SCL Pin number */ #else #if defined (I2C2_SDA_PIN) I2C2_SDA_PIN, /* SDA Pin number */ #else -1, /* SDA Pin number */ #endif #if defined (I2C2_SCL_PIN) I2C2_SCL_PIN, /* SCL Pin number */ #else -1, /* SCL Pin number */ #endif #endif #if defined (I2C2_SMBA_PIN) I2C2_SMBA_PIN, /* SMBA Pin number */ #else -1, /* SMBA Pin number */ #endif &sig_TWI2_EV, /* Event signal */ &sig_TWI2_ER, /* Error signal */ NULL, /* icb_msg */ NULL /* icb_queue */ }; #if defined(I2C3_BASE) static STM32_I2CCB i2c3cb = { I2C3_BASE, /* Register Base */ #if defined (I2C3_SDA_PIN) I2C3_SDA_PIN, /* SDA Pin number */ #else -1, /* SDA Pin number */ #endif #if defined (I2C3_SCL_PIN) I2C3_SCL_PIN, /* SDA Pin number */ #else -1, /* SDA Pin number */ #endif #if defined (I2C3_SMBA_PIN) I2C3_SMBA_PIN, /* SDA Pin number */ #else -1, /* SDA Pin number */ #endif &sig_TWI3_EV, /* Event signal */ &sig_TWI3_ER, /* Error signal */ NULL, /* icb_msg */ NULL /* icb_queue */ }; #endif NUTI2C_BUS i2cBus1Stm32 = { &i2c1cb, /* bus_icb */ I2cBusInit, /* bus_init */ I2cBusConf, /* bus_configure */ I2cBusProbe,/* bus_probe */ I2cBusTran, /* bus_transceive */ 100, /* bus_timeout */ 0, /* bus_rate */ 0, /* bus_flags */ NULL /* bus_mutex */ }; NUTI2C_BUS i2cBus2Stm32 = { &i2c2cb, /* bus_icb */ I2cBusInit, /* bus_init */ I2cBusConf, /* bus_configure */ I2cBusProbe,/* bus_probe */ I2cBusTran, /* bus_transceive */ 100, /* bus_timeout */ 0, /* bus_rate */ 0, /* bus_flags */ NULL /* bus_mutex */ }; #if defined(I2C3_BASE) NUTI2C_BUS i2cBus3Stm32 = { &i2c3cb, /* bus_icb */ I2cBusInit, /* bus_init */ I2cBusConf, /* bus_configure */ I2cBusProbe,/* bus_probe */ I2cBusTran, /* bus_transceive */ 100, /* bus_timeout */ 0, /* bus_rate */ 0, /* bus_flags */ NULL /* bus_mutex */ }; #endif