From a5cec9ca65e43da56b11dc11c706598d72edd78c Mon Sep 17 00:00:00 2001 From: "yungchi@cs.nctu.edu.tw" Date: Wed, 21 Sep 2011 07:50:43 +0000 Subject: [PATCH] Create a driver diectory Add I2C driver and a 24LC024H i2c eeprom usage example Now only support I2C1, not yet fully support I2C2 ****GPIO Config**** I2C1 SDA -> PB8 I2C1 SCL -> PB9 git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1716 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- bsp/stm32f20x/Drivers/24LCxx.c | 153 ++++++++ bsp/stm32f20x/Drivers/i2c.c | 618 +++++++++++++++++++++++++++++++++ bsp/stm32f20x/Drivers/i2c.h | 137 ++++++++ 3 files changed, 908 insertions(+) create mode 100644 bsp/stm32f20x/Drivers/24LCxx.c create mode 100644 bsp/stm32f20x/Drivers/i2c.c create mode 100644 bsp/stm32f20x/Drivers/i2c.h diff --git a/bsp/stm32f20x/Drivers/24LCxx.c b/bsp/stm32f20x/Drivers/24LCxx.c new file mode 100644 index 000000000..278ccfecb --- /dev/null +++ b/bsp/stm32f20x/Drivers/24LCxx.c @@ -0,0 +1,153 @@ +#include +#include "i2c.h" + +#define EE_Address 0xA0 + +#define EE24LC024H + +/* + Note: If eeprom size lager then 256 byte, you must define EE_ADDR_SIZE == I2C_MEM_2Bytes +*/ +#ifdef EE24LC024H +#define EE_PageSize 8 +#define EE_ADDR_SIZE I2C_MEM_1Byte +#define EE_MEM_SIZE 256 +#define EE_PageSize 16 +#endif + +static struct rt_device ee_dev; + +uint32_t EE_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t NumByteToRead) +{ + return I2C_IORW(I2C1, pBuffer, NumByteToRead, ReadAddr, EE_Address | 0x01, I2C_MEM_1Byte ); +} + +uint32_t EE_WritePage(uint8_t* pBuffer, uint16_t WriteAddr) +{ + I2C_IORW(I2C1, pBuffer, EE_PageSize , WriteAddr, EE_Address , EE_ADDR_SIZE ); + + /*if( I2C_AcknowledgePolling(I2C1 , EE_Address) == Error ) + rt_kprintf("EE ACK failed\n");*/ + rt_thread_delay(50); +} +uint32_t EE_WriteByte(uint8_t* pBuffer, uint16_t WriteAddr) +{ + I2C_IORW(I2C1, pBuffer, 1 , WriteAddr, EE_Address, EE_ADDR_SIZE ); + + /*if( I2C_AcknowledgePolling(I2C1 , EE_Address) == Error ) + rt_kprintf("EE ACK failed\n");*/ + rt_thread_delay(50); +} + +Status EE_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite) +{ + uint8_t NumOfPage = 0, NumOfSingle = 0; + uint16_t Addr = 0,count = 0; + uint8_t* ptr = pBuffer; + + Addr = WriteAddr; + + count = NumByteToWrite; + + if( (WriteAddr + NumByteToWrite ) > EE_MEM_SIZE ) + return Error; + + while( count >= EE_PageSize ) + { + EE_WritePage(ptr, Addr); + Addr += EE_PageSize; + count -= EE_PageSize; + ptr += EE_PageSize; + } + + while( count ) + { + EE_WriteByte( ptr++, Addr++ ); + count--; + } + + return Success; + +} + +static rt_err_t ee24LCxx_init (rt_device_t dev) +{ + return RT_EOK; +} +static rt_size_t ee24LCxx_read( rt_device_t dev, rt_off_t pos, void *buf, rt_size_t size ) +{ + if( EE_ReadBuffer(buf, pos, size) == Success ) + return size; + else + return -1; +} + +static rt_size_t ee24LCxx_write( rt_device_t dev, rt_off_t pos, void *buf, rt_size_t size ) +{ + if( EE_WriteBuffer(buf, pos, size) == Success ) + return size; + else + return -1; +} + +static rt_err_t ee24LCxx_open(rt_device_t dev, rt_uint16_t oflag) +{ + return RT_EOK; +} + +static rt_err_t ee24LCxx_close(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t ee24LCxx_control (rt_device_t dev, rt_uint8_t cmd, void *args) +{ + return RT_EOK; +} + +void ee24LCxx_hw_init() +{ + I2C1_INIT(); + + ee_dev.init = ee24LCxx_init; + ee_dev.open = ee24LCxx_open; + ee_dev.close = ee24LCxx_close; + ee_dev.read = ee24LCxx_read; + ee_dev.write = ee24LCxx_write; + ee_dev.control = ee24LCxx_control; + ee_dev.type = RT_Device_Class_I2C; + + + rt_device_register(&ee_dev, "eeprom", RT_DEVICE_FLAG_RDWR); +} + +void ee_test() +{ + char buf[256], read[256]; + int i,ret; + + rt_device_t dev; + dev = rt_device_find("eeprom"); + + for(i = 0; i < 256; i++ ) + { + buf[i] = i; + read[i] = 0; + } + if( rt_device_write(dev, 0, buf, 256 ) == 256 ) + rt_kprintf("Write Success\n"); + + rt_device_read(dev, 0, read, 256 ); + + for(i = 0; i < 256; i++ ) + { + if( buf[i] != read[i] ) + rt_kprintf("EE Failed %X != %X at %d\n", buf[i], read[i], i); + } + rt_kprintf("Finsh\n"); + +} +#ifdef RT_USING_FINSH +#include +FINSH_FUNCTION_EXPORT(ee_test, test system); +#endif diff --git a/bsp/stm32f20x/Drivers/i2c.c b/bsp/stm32f20x/Drivers/i2c.c new file mode 100644 index 000000000..63dc5f0f7 --- /dev/null +++ b/bsp/stm32f20x/Drivers/i2c.c @@ -0,0 +1,618 @@ + +#include +#include "i2c.h" +#include "stm32f2xx_rcc.h" +#include "stm32f2xx_i2c.h" +#include "stm32f2xx_dma.h" + +#define EV_SB 1 +#define EV_ADDR (1<<1) +#define EV_STOPF (1<<2) +#define EV_BTF (1<<3) +#define ERR_ARLO (1<<4) +#define ERR_AF (1<<5) +#define ERR_OVR (1<<6) +#define ERR_PECERR (1<<7) +#define ERR_BERR (1<<8) +#define I2C_COMPLETE (1<<9) + +#define I2C_BUSY 1 +#define I2C_FREE 2 + +#define I2C_WRITE 0 +#define I2C_READ_DMA 1 +#define I2C_READ_POLLING 2 +#define I2C_READ_INTERRUPT 3 + +#define I2C_TRACE(...) + +enum i2c_state {S1=0, S2, S2_1, S2_2, S3, S4, S5, S6, S_STOP}; + + + +extern void rt_hw_led_on(rt_uint32_t n); +extern void rt_hw_led_off(rt_uint32_t n); + +DMA_InitTypeDef I2CDMA_InitStructure; +uint32_t I2CDirection = I2C_DIRECTION_TX; +uint32_t i2cErrorNo = 0; + +struct rt_event i2c_event; +static rt_mutex_t i2c_mux; + +__IO uint8_t DevAddr; +static uint8_t* i2c_buf, *MemAddr, i2cStatus, i2cFlag, i2cPhase, memtype, i2c1_init_flag = 0; +static uint32_t BufSize; + +I2C_ProgrammingModel I2CMode = DMA; + + +Status I2C_Free_Bus(I2C_TypeDef* I2Cx, u32 timeout ); +void I2C_DMAConfig(I2C_TypeDef* I2Cx, uint8_t* pBuffer, uint32_t BufferSize, uint32_t Direction); + +void dump_i2c_register(I2C_TypeDef* I2Cx) +{ + if(I2Cx == I2C1 ) + I2C_TRACE("======I2C1======\n"); + else + I2C_TRACE("======I2C2======\n"); + I2C_TRACE("CR1: 0x%x\tCR2: 0x%x\n", I2Cx->CR1, I2Cx->CR2); + I2C_TRACE("SR1: 0x%x\tSR2: 0x%x\n", I2Cx->SR1, I2Cx->SR2); + +} + +/*TODO: If your device need more time to initialize I2C bus or waiting memory write, you can use I2C_AcknowledgePolling avoid I2C bus lose.*/ +Status I2C_AcknowledgePolling(I2C_TypeDef* I2Cx ,uint8_t Addr) +{ + uint32_t timeout = 0xFFFF, ret; + uint16_t tmp; + ret = rt_mutex_take(i2c_mux, RT_WAITING_FOREVER ); + + if( ret == RT_EOK ) + { + do{ + if( timeout-- <= 0 ) + { + I2C_ClearFlag(I2Cx,I2C_FLAG_AF); + I2Cx->CR1 |= CR1_STOP_Set; + rt_mutex_release(i2c_mux); + return Error; + } + + I2Cx->CR1 |= CR1_START_Set; + tmp = I2Cx->SR1;//²M°£SB¦ì + I2Cx->DR = Addr; + + }while((I2Cx->SR1&0x0002) != 0x0002); + + I2C_ClearFlag(I2Cx,I2C_FLAG_AF); + I2Cx->CR1 |= CR1_STOP_Set; + while ((I2Cx->CR1&0x200) == 0x200); + rt_kprintf( "AcknowledgePolling OK\n"); + rt_mutex_release(i2c_mux); + return Success; + } + else + return Error; +} + +/* + Only 1 byte READ using Interrupt or Polling otherwise using DMA +*/ +void I2C1_EV_IRQHandler() +{ + __IO uint16_t regSR1, regSR2; + __IO uint32_t regSR; + int i=10; + + rt_interrupt_enter(); + //rt_hw_led_on(10); + regSR1 = I2C1->SR1; + regSR2 = I2C1->SR2; + regSR = (regSR2 << 16) | regSR1; + //rt_kprintf("EV=> SR1: 0x%x\tSR2: 0x%x\tSR: 0x%x status: %d\n", regSR1, regSR2, regSR, i2cStatus); + + if( (regSR & I2C_EVENT_MASTER_MODE_SELECT) == I2C_EVENT_MASTER_MODE_SELECT) //EV5 + { + + if( i2cStatus == S1 ) //Send TX Command + { + I2C1->DR = DevAddr & 0xFE; + i2cStatus = S2; + } + else if( i2cStatus == S4 ) //Send RX Command + { + I2C1->DR = DevAddr | 0x01; + i2cStatus = S5; + } + + + regSR1 = 0; + regSR2 = 0; + + } + if( (regSR & I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)== I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) //EV6 + { + switch( i2cStatus ) + { + case S2: //Send 1st memory address phase + { + //I2C_DMACmd(I2C1, ENABLE); + I2C1->DR = MemAddr[0]; + if( memtype == I2C_MEM_1Byte ) + i2cStatus = S2_2; + else if( memtype == I2C_MEM_2Bytes ) + i2cStatus = S2_1; + } + break; + case S5: //Set RX buffer phase + { + if( i2cFlag == I2C_READ_DMA ) + { + I2C_DMAConfig(I2C1, i2c_buf, BufSize, I2C_DIRECTION_RX); + I2C1->CR2 |= CR2_LAST_Set | CR2_DMAEN_Set; + DMA_ITConfig( I2C1_DMA_CHANNEL_RX, DMA_IT_TC, ENABLE); + } + else if( i2cFlag == I2C_READ_INTERRUPT ) + { + I2C1->CR2 |= I2C_IT_BUF; + I2C1->CR1 &= CR1_ACK_Reset; + /* Program the STOP */ + I2C1->CR1 |= CR1_STOP_Set; + } + i2cStatus = S6; + } + break; + } + + regSR1 = 0; + regSR2 = 0; + //dump_i2c_register(I2C1); + } + if((regSR & I2C_EVENT_MASTER_BYTE_RECEIVED) == I2C_EVENT_MASTER_BYTE_RECEIVED) //EV7 + { + //Interrupt RX complete phase + if( i2cStatus == S6 && i2cFlag == I2C_READ_INTERRUPT ) + { + *i2c_buf = I2C1->DR; + i2cStatus = S_STOP; + rt_event_send(&i2c_event, I2C_COMPLETE); + } + } + if( (regSR & I2C_EVENT_MASTER_BYTE_TRANSMITTED) == I2C_EVENT_MASTER_BYTE_TRANSMITTED ) //EV8_2 + { + //Start TX/RX phase + if(i2cStatus == S3) + { + DMA_ClearFlag(I2C1_DMA_CHANNEL_TX, DMA_FLAG_TCIF6 ); + DMA_Cmd(I2C1_DMA_CHANNEL_TX, DISABLE); + switch (i2cFlag) + { + case I2C_WRITE: + i2cStatus = S_STOP; + I2C1->CR1 |= CR1_STOP_Set; + rt_event_send(&i2c_event, I2C_COMPLETE); + break; + + case I2C_READ_DMA: + i2cStatus = S4; + I2C1->CR1 |= CR1_START_Set; + break; + + case I2C_READ_POLLING: + i2cStatus = S_STOP; + rt_event_send(&i2c_event, I2C_COMPLETE); + I2C1->CR2 &= ~(CR2_LAST_Set | I2C_IT_EVT | CR2_DMAEN_Set); + I2C1->CR1 |= CR1_START_Set; + break; + + case I2C_READ_INTERRUPT: + i2cStatus = S4; + I2C1->CR1 |= CR1_START_Set; + break; + } + } + if( i2cStatus == S2_1 ) //Send 2nd memory address + { + if( memtype == I2C_MEM_2Bytes ) //memory address has 2 bytes + { + I2C1->DR = MemAddr[1]; + i2cStatus = S2_2; + } + if( i2cFlag == I2C_READ_POLLING || i2cFlag == I2C_READ_DMA || i2cFlag == I2C_READ_INTERRUPT) + { + i2cStatus = S3; + } + } + if( i2cStatus == S2_2 ) //Set TX DAM phase + { + I2C_DMAConfig(I2C1, i2c_buf, BufSize, I2C_DIRECTION_TX); + I2C1->CR2 |= CR2_DMAEN_Set; + i2cStatus = S3; + } + } + + rt_interrupt_leave(); + +} + +void DMA1_Stream6_IRQHandler(void) //I2C1 TX +{ + rt_interrupt_enter(); + if (DMA_GetITStatus(I2C1_DMA_CHANNEL_TX, DMA_IT_TCIF6)) + { + I2C_TRACE("TXTC\n"); + DMA_ClearFlag(I2C1_DMA_CHANNEL_TX, DMA_FLAG_TCIF6 ); + + } + rt_interrupt_leave(); +} + +void DMA1_Stream0_IRQHandler(void) //I2C1 RX +{ + + rt_interrupt_enter(); + + if (DMA_GetITStatus(I2C1_DMA_CHANNEL_RX, DMA_IT_TCIF0)) + { + I2C_TRACE("RXTC\n"); + /* clear DMA flag */ + DMA_ClearFlag(I2C1_DMA_CHANNEL_RX, DMA_FLAG_TCIF0 ); + DMA_ITConfig( I2C1_DMA_CHANNEL_RX, DMA_IT_TC, DISABLE); + DMA_Cmd(I2C1_DMA_CHANNEL_RX, DISABLE); + if( i2cStatus == S6 ) + { + i2cStatus = S_STOP; + I2C1->CR1 |= CR1_STOP_Set; + rt_event_send(&i2c_event, I2C_COMPLETE); + } + } + if (DMA_GetITStatus(I2C1_DMA_CHANNEL_RX, DMA_IT_HTIF0)) + { + I2C_TRACE("RXHT\n"); + DMA_ClearFlag(I2C1_DMA_CHANNEL_RX, DMA_FLAG_HTIF0 ); + } + if (DMA_GetITStatus(I2C1_DMA_CHANNEL_RX, DMA_IT_TEIF0)) + { + I2C_TRACE("RXTE\n"); + DMA_ClearFlag(I2C1_DMA_CHANNEL_RX, DMA_FLAG_TEIF0 ); + } + if (DMA_GetITStatus(I2C1_DMA_CHANNEL_RX, DMA_IT_FEIF0)) + { + I2C_TRACE("RXFE\n"); + DMA_ClearFlag(I2C1_DMA_CHANNEL_RX, DMA_FLAG_FEIF0 ); + } + if (DMA_GetITStatus(I2C1_DMA_CHANNEL_RX, DMA_IT_DMEIF0)) + { + I2C_TRACE("RXDME\n"); + DMA_ClearFlag(I2C1_DMA_CHANNEL_RX, DMA_FLAG_DMEIF0 ); + } + + rt_interrupt_leave(); +} + +void I2C1_ER_IRQHandler() +{ + __IO uint16_t regSR1, regSR2; + + i2cErrorNo = 0; + regSR1 = I2C1->SR1; + I2C_TRACE("I2C Error SR1= 0x%X CR1 = 0x%X\n" , regSR1, I2C1->CR1); + if( (regSR1 & SR1_AF_Set) == SR1_AF_Set) + { + I2C1->SR1 &= ~SR1_AF_Set; + i2cErrorNo |= ERR_AF; + I2C_TRACE("ACK failure\n"); + } + if( (regSR1 & SR1_BERR_Set) == SR1_BERR_Set) + { + I2C1->SR1 &= ~SR1_BERR_Set; + i2cErrorNo |= ERR_BERR; + I2C_TRACE("Bus Error\n"); + } + if( (regSR1 & SR1_ARLO_Set) == SR1_ARLO_Set) + { + I2C1->SR1 &= ~SR1_ARLO_Set; + i2cErrorNo |= ERR_ARLO; + I2C_TRACE("Arblitation lost\n"); + } + //dump_i2c_register(I2C1); + +} +Status I2C_Free_Bus(I2C_TypeDef* I2Cx, u32 timeout ) +{ + /*u32 i = 0; + u16 tmp = 0; + GPIO_InitTypeDef GPIO_InitStructure; + + tmp = I2Cx->SR2; + + while( tmp & SR2_BUSY ) + { + if( i++ < timeout ) + { + if( I2Cx == I2C1 ) + { + //rt_kprintf("Free Bus!\n"); + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + GPIO_SetBits(GPIOB, GPIO_Pin_6); + GPIO_SetBits(GPIOB, GPIO_Pin_7); + + } + else if( I2Cx == I2C2 ) + { + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + GPIO_ResetBits(GPIOB, GPIO_Pin_10); + } + rt_thread_delay(10); + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; + GPIO_Init(GPIOB, &GPIO_InitStructure); + I2C_Cmd(I2Cx, DISABLE); + I2C_Cmd(I2Cx, ENABLE); + } + else + return Error; + tmp = I2Cx->SR2; + } */ + return Success; + +} + +/* + I2Cx: I2C1 or I2C2 (Now it only support I2C1) + pBuffer: Buffer point + NumByteToRW: Number of bytes read/write + SlaveAddress: device address + MemType: 1 = memory address size 1 bytes, 2 = memory address size 2 bytes +*/ +Status I2C_IORW(I2C_TypeDef* I2Cx, uint8_t* pBuffer, uint32_t NumByteToRW, uint16_t memAddr, uint8_t SlaveAddress, uint8_t MemType ) +{ + uint32_t ev, Timeout=0xFFFF; + uint16_t temp, temp2; + static uint32_t call_cnt = 0, i; + Status ret; + + ret = rt_mutex_take(i2c_mux, RT_WAITING_FOREVER ); + if( ret == RT_EOK ) + { + ret = Success; + DevAddr = SlaveAddress; + BufSize = NumByteToRW; + i2c_buf = pBuffer; + memtype = MemType; + + MemAddr = (uint8_t*)&memAddr; + I2CDirection = I2C_DIRECTION_TX; + + I2CMode = DMA; + + i2cStatus = S1; + if( SlaveAddress & 0x01 ) + { + if( BufSize == 1 ) + i2cFlag = I2C_READ_INTERRUPT; //I2C_READ_POLLING; + else + i2cFlag = I2C_READ_DMA; + } + else + i2cFlag = I2C_WRITE; + I2Cx->CR2 |= I2C_IT_ERR | I2C_IT_EVT;// | CR2_DMAEN_Set; + + I2Cx->CR1 |= CR1_START_Set; + + Timeout = 0xFFFF; + if( rt_event_recv( &i2c_event, I2C_COMPLETE, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &ev ) != RT_EOK ) {ret = Error; goto i2cError;} + + if( i2cFlag == I2C_READ_POLLING ) + { + while ((I2Cx->SR1&0x0001) != 0x0001) + if (Timeout-- == 0) {ret = Error; goto i2cError;} + Timeout = 0xFFFF; + I2Cx->DR = DevAddr; + /* Wait until ADDR is set: EV6 */ + while ((I2Cx->SR1&0x0002) != 0x0002) + { + if (Timeout-- == 0){ret = Error; goto i2cError;} + } + /* Clear ACK bit */ + I2Cx->CR1 &= CR1_ACK_Reset; + /* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3 + software sequence must complete before the current byte end of transfer */ + __disable_irq(); + /* Clear ADDR flag */ + temp = I2Cx->SR2; + /* Program the STOP */ + I2Cx->CR1 |= CR1_STOP_Set; + /* Re-enable IRQs */ + __enable_irq(); + /* Wait until a data is received in DR register (RXNE = 1) EV7 */ + while ((I2Cx->SR1 & 0x00040) != 0x000040)if (Timeout-- == 0){ret = Error; goto i2cError;} + /* Read the data */ + *i2c_buf = I2Cx->DR; + /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */ + while ((I2Cx->CR1&0x200) == 0x200)if (Timeout-- == 0){ret = Error; goto i2cError;} + /* Enable Acknowledgement to be ready for another reception */ + I2Cx->CR1 |= CR1_ACK_Set; + } + else + { + while ((I2Cx->CR1&0x200) == 0x200) + { + if (Timeout-- == 0) {ret = Error; break;} + } + if( i2cFlag == I2C_READ_INTERRUPT ) + I2Cx->CR1 |= CR1_ACK_Set; + } + i2cError: + if( ret == Error ) + { + /* TODO: i2c error handler */ + /* Need check i2cErrorNo and Reset I2C bus */ + } + I2Cx->CR2 &= ~CR2_FREQ_Reset; + //dump_i2c_register(I2C1); + rt_mutex_release(i2c_mux); + return ret; + } + else + return Error; + +} + + +void I2C1_INIT() +{ + GPIO_InitTypeDef GPIO_InitStructure; + I2C_InitTypeDef I2C_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + if( i2c1_init_flag == 0 ) + { + /* Enable the I2C clock */ + RCC_APB1PeriphClockCmd(I2C1_CLK, ENABLE); + /* GPIOB clock enable */ + RCC_AHB1PeriphClockCmd(I2C1_GPIO_CLK, ENABLE); + /* Enable the DMA1 clock */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); + + //Reset GPIO + GPIO_InitStructure.GPIO_Pin = I2C1_SDA_PIN | I2C1_SCL_PIN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(I2C1_GPIO_PORT, &GPIO_InitStructure); + + /* Connect PXx to I2C_SCL*/ + GPIO_PinAFConfig(I2C1_GPIO_PORT, I2C1_SDA_SOURCE, GPIO_AF_I2C1); + + /* Connect PXx to I2C_SDA*/ + GPIO_PinAFConfig(I2C1_GPIO_PORT, I2C1_SCL_SOURCE, GPIO_AF_I2C1); + + /* Enable I2C1 reset state */ + RCC_APB1PeriphResetCmd(I2C1_CLK, ENABLE); + /* Release I2C1 from reset state */ + RCC_APB1PeriphResetCmd(I2C1_CLK, DISABLE); + + I2C_DeInit(I2C1); + I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; + I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; + I2C_InitStructure.I2C_OwnAddress1 = OwnAddress1; + I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; + I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; + I2C_InitStructure.I2C_ClockSpeed = ClockSpeed; + I2C_Init(I2C1, &I2C_InitStructure); + + I2C_Cmd(I2C1, ENABLE); + + /* Configure and enable I2C1 event interrupt -------------------------------*/ + NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + /* Configure and enable I2C1 DMA interrupt -------------------------------*/ + NVIC_InitStructure.NVIC_IRQChannel = I2C1_DMA_TX_IRQn; + NVIC_Init(&NVIC_InitStructure); + + NVIC_InitStructure.NVIC_IRQChannel = I2C1_DMA_RX_IRQn; + NVIC_Init(&NVIC_InitStructure); + + /* Configure and enable I2C1 error interrupt -------------------------------*/ + NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; + NVIC_Init(&NVIC_InitStructure); + + /* I2C1 TX DMA Channel configuration */ + DMA_Cmd(I2C1_DMA_CHANNEL_TX, DISABLE); + DMA_DeInit(I2C1_DMA_CHANNEL_TX); + I2CDMA_InitStructure.DMA_Channel = DMA_Channel_1; + I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address; + I2CDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0; /* This parameter will be configured durig communication */ + I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; /* This parameter will be configured durig communication */ + I2CDMA_InitStructure.DMA_BufferSize = 0xFFFF; /* This parameter will be configured durig communication */ + I2CDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + I2CDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + I2CDMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + I2CDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + I2CDMA_InitStructure.DMA_Mode = DMA_Mode_Normal; + I2CDMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; + //I2CDMA_InitStructure.DMA_M2M = DMA_M2M_Disable; + I2CDMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + I2CDMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; + I2CDMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + I2CDMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_Init(I2C1_DMA_CHANNEL_TX, &I2CDMA_InitStructure); + + /* I2C1 RX DMA Channel configuration */ + DMA_Cmd(I2C1_DMA_CHANNEL_RX, DISABLE); + DMA_DeInit(I2C1_DMA_CHANNEL_RX); + DMA_Init(I2C1_DMA_CHANNEL_RX, &I2CDMA_InitStructure); + + //I2C_AcknowledgePolling(I2C1, 0x70); + + rt_event_init(&i2c_event, "i2c_event", RT_IPC_FLAG_FIFO ); + i2c_mux = rt_mutex_create("i2c_mux", RT_IPC_FLAG_FIFO ); + i2c1_init_flag = 1; + } +} + +void I2C_DMAConfig(I2C_TypeDef* I2Cx, uint8_t* pBuffer, uint32_t BufferSize, uint32_t Direction) +{ + + I2CDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)pBuffer; + I2CDMA_InitStructure.DMA_BufferSize = (uint32_t)BufferSize; + /* Initialize the DMA with the new parameters */ + if (Direction == I2C_DIRECTION_TX) + { + /* Configure the DMA Tx Channel with the buffer address and the buffer size */ + I2CDMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + + if (I2Cx == I2C1) + { + I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address; + //DMA_Cmd(I2C1_DMA_CHANNEL_TX, DISABLE); + DMA_Init(I2C1_DMA_CHANNEL_TX, &I2CDMA_InitStructure); + DMA_Cmd(I2C1_DMA_CHANNEL_TX, ENABLE); + } + else + { + I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address; + //DMA_Cmd(I2C2_DMA_CHANNEL_TX, DISABLE); + DMA_Init(I2C2_DMA_CHANNEL_TX, &I2CDMA_InitStructure); + DMA_Cmd(I2C2_DMA_CHANNEL_TX, ENABLE); + } + + } + else /* Reception */ + { + /* Configure the DMA Rx Channel with the buffer address and the buffer size */ + I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; + + if (I2Cx == I2C1) + { + I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address; + //DMA_Cmd(I2C1_DMA_CHANNEL_RX, DISABLE); + DMA_Init(I2C1_DMA_CHANNEL_RX, &I2CDMA_InitStructure); + DMA_Cmd(I2C1_DMA_CHANNEL_RX, ENABLE); + } + else + { + I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address; + // DMA_Cmd(I2C2_DMA_CHANNEL_RX, DISABLE); + DMA_Init(I2C2_DMA_CHANNEL_RX, &I2CDMA_InitStructure); + DMA_Cmd(I2C2_DMA_CHANNEL_RX, ENABLE); + } + + } +} + diff --git a/bsp/stm32f20x/Drivers/i2c.h b/bsp/stm32f20x/Drivers/i2c.h new file mode 100644 index 000000000..b8453e780 --- /dev/null +++ b/bsp/stm32f20x/Drivers/i2c.h @@ -0,0 +1,137 @@ +#ifndef I2C_H +#define I2C_H + +#include "stm32f2xx.h" + +/* Exported constants --------------------------------------------------------*/ + +#define SR1_AF_Set ((uint16_t)0x0400) +#define SR1_ARLO_Set ((uint16_t)0x0200) +#define SR1_BERR_Set ((uint16_t)0x0100) +#define SR1_ADDR_Set ((uint16_t)0x0002) +#define SR1_SB_Set ((uint16_t)0x0001) + + +#define SR2_BUSY ((uint16_t)0x0002) +#define SR2_MSL ((uint16_t)0x0001) + +#define CR1_SWRST_Set ((uint16_t)0x8000) +/* I2C SPE mask */ +#define CR1_PE_Set ((uint16_t)0x0001) +#define CR1_PE_Reset ((uint16_t)0xFFFE) + +/* I2C START mask */ +#define CR1_START_Set ((uint16_t)0x0100) +#define CR1_START_Reset ((uint16_t)0xFEFF) + +#define CR1_POS_Set ((uint16_t)0x0800) +#define CR1_POS_Reset ((uint16_t)0xF7FF) + +/* I2C STOP mask */ +#define CR1_STOP_Set ((uint16_t)0x0200) +#define CR1_STOP_Reset ((uint16_t)0xFDFF) + +/* I2C ACK mask */ +#define CR1_ACK_Set ((uint16_t)0x0400) +#define CR1_ACK_Reset ((uint16_t)0xFBFF) + +/* I2C ENARP mask */ +#define CR1_ENARP_Set ((uint16_t)0x0010) +#define CR1_ENARP_Reset ((uint16_t)0xFFEF) + +/* I2C NOSTRETCH mask */ +#define CR1_NOSTRETCH_Set ((uint16_t)0x0080) +#define CR1_NOSTRETCH_Reset ((uint16_t)0xFF7F) + +/* I2C registers Masks */ +#define CR1_CLEAR_Mask ((uint16_t)0xFBF5) + +/* I2C DMAEN mask */ +#define CR2_DMAEN_Set ((uint16_t)0x0800) +#define CR2_DMAEN_Reset ((uint16_t)0xF7FF) + +/* I2C LAST mask */ +#define CR2_LAST_Set ((uint16_t)0x1000) +#define CR2_LAST_Reset ((uint16_t)0xEFFF) + +/* I2C FREQ mask */ +#define CR2_FREQ_Reset ((uint16_t)0xFFC0) + +/* I2C ADD0 mask */ +#define OAR1_ADD0_Set ((uint16_t)0x0001) +#define OAR1_ADD0_Reset ((uint16_t)0xFFFE) + +/* I2C ENDUAL mask */ +#define OAR2_ENDUAL_Set ((uint16_t)0x0001) +#define OAR2_ENDUAL_Reset ((uint16_t)0xFFFE) + +/* I2C ADD2 mask */ +#define OAR2_ADD2_Reset ((uint16_t)0xFF01) + +/* I2C F/S mask */ +#define CCR_FS_Set ((uint16_t)0x8000) + +/* I2C CCR mask */ +#define CCR_CCR_Set ((uint16_t)0x0FFF) + +/* I2C FLAG mask */ +#define FLAG_Mask ((uint32_t)0x00FFFFFF) + +/* I2C Interrupt Enable mask */ +#define ITEN_Mask ((uint32_t)0x07000000) + + +#define I2C_IT_BUF ((uint16_t)0x0400) +#define I2C_IT_EVT ((uint16_t)0x0200) +#define I2C_IT_ERR ((uint16_t)0x0100) + + +#define ClockSpeed 400000 + +#define I2C_DIRECTION_TX 0 +#define I2C_DIRECTION_RX 1 + +#define OwnAddress1 0x28 +#define OwnAddress2 0x30 + + +#define I2C1_DMA_CHANNEL_TX DMA1_Stream6 +#define I2C1_DMA_CHANNEL_RX DMA1_Stream0 +#define I2C1_DMA_TX_IRQn DMA1_Stream6_IRQn +#define I2C1_DMA_RX_IRQn DMA1_Stream0_IRQn + +#define I2C2_DMA_CHANNEL_TX DMA1_Stream2 +#define I2C2_DMA_CHANNEL_RX DMA1_Stream7 + +#define I2C1_DR_Address 0x40005410 +#define I2C2_DR_Address 0x40005810 + +#define I2C1_SDA_PIN GPIO_Pin_9 +#define I2C1_SCL_PIN GPIO_Pin_8 +#define I2C1_SDA_SOURCE GPIO_PinSource9 +#define I2C1_SCL_SOURCE GPIO_PinSource8 +#define I2C1_GPIO_PORT GPIOB +#define I2C1_GPIO_CLK RCC_AHB1Periph_GPIOB +#define I2C1_CLK RCC_APB1Periph_I2C1 + +#define I2C_MEM_1Byte 1 +#define I2C_MEM_2Bytes 2 + +typedef enum +{ + Error = 0, + Success = !Error +}Status; + +typedef enum +{ + Polling = 0x00, + Interrupt = 0x01, + DMA = 0x02 +} I2C_ProgrammingModel; + +void I2C1_INIT(); +Status I2C_AcknowledgePolling(I2C_TypeDef* I2Cx ,uint8_t Addr); +Status I2C_IORW(I2C_TypeDef* I2Cx, uint8_t* pBuffer, uint32_t NumByteToRead, uint16_t memAddr, uint8_t SlaveAddress , uint8_t MemType ); + +#endif \ No newline at end of file -- GitLab