diff --git a/Config.h b/Config.h index b7d146f..35c7e52 100644 --- a/Config.h +++ b/Config.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017,2018 by Andy Uribe CA6JAU + * Copyright (C) 2017,2018,2019 by Andy Uribe CA6JAU * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,6 +58,10 @@ // Host communication selection: // #define STM32_USART1_HOST #define STM32_USB_HOST +// #define STM32_I2C_HOST + +// I2C host address: +#define I2C_ADDR 0x22 // Enable mode detection: #define ENABLE_SCAN_MODE diff --git a/Globals.h b/Globals.h index d50e1c2..ffc0ad8 100644 --- a/Globals.h +++ b/Globals.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX - * Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU + * Copyright (C) 2016,2017,2018,2019 by Andy Uribe CA6JAU * Copyright (C) 2019 by Florian Wolters DF2ET * * This program is free software; you can redistribute it and/or modify @@ -85,6 +85,7 @@ const uint8_t MARK_NONE = 0x00U; #include "CalDMR.h" #include "Debug.h" #include "Utils.h" +#include "I2CHost.h" extern MMDVM_STATE m_modemState; extern MMDVM_STATE m_calState; @@ -145,5 +146,9 @@ extern CCalRSSI calRSSI; extern CCWIdTX cwIdTX; +#if defined(STM32_I2C_HOST) +extern CI2CHost i2c; +#endif + #endif diff --git a/I2CHost.cpp b/I2CHost.cpp new file mode 100644 index 0000000..e80a096 --- /dev/null +++ b/I2CHost.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2019 by Andy Uribe CA6JAU + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" + +#if defined(STM32_I2C_HOST) + +#include "Globals.h" +#include "I2CHost.h" + +extern "C" { + void I2C2_EV_IRQHandler(void) { + i2c.I2C_EVHandler(); + } + + void I2C2_ER_IRQHandler(void) { + if (I2C_GetITStatus(I2C2, I2C_IT_AF)) { + I2C_ClearITPendingBit(I2C2, I2C_IT_AF); + } + } +} + +CI2CHost::CI2CHost() +{ +} + +void CI2CHost::Init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + I2C_InitTypeDef I2C_InitStructure; + + RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); + + // Configure I2C GPIOs + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + // Configure the I2C event interrupt + NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 15; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + // Configure the I2C error interrupt + NVIC_InitStructure.NVIC_IRQChannel = I2C2_ER_IRQn; + NVIC_Init(&NVIC_InitStructure); + + // I2C configuration + I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; + I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; + I2C_InitStructure.I2C_OwnAddress1 = I2C_ADDR << 1; + I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; + I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; + I2C_InitStructure.I2C_ClockSpeed = I2C_CLK_FREQ; + + // Enable I2C + I2C_Cmd(I2C2, ENABLE); + // Apply I2C configuration + I2C_Init(I2C2, &I2C_InitStructure); + + I2C_ITConfig(I2C2, I2C_IT_EVT, ENABLE); + I2C_ITConfig(I2C2, I2C_IT_BUF, ENABLE); + I2C_ITConfig(I2C2, I2C_IT_ERR, ENABLE); + + // Initialize the FIFOs + txFIFO_head = 0U; + txFIFO_tail = 0U; + rxFIFO_head = 0U; + rxFIFO_tail = 0U; +} + +void CI2CHost::I2C_EVHandler(void) { + uint32_t event = I2C_GetLastEvent(I2C2); + + switch (event) { + case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: + break; + case I2C_EVENT_SLAVE_BYTE_RECEIVED: + if (rxFIFO_level() < I2C_RX_FIFO_SIZE) { + rxFIFO[rxFIFO_head] = I2C_ReceiveData(I2C2); + rxFIFO_head++; + if (rxFIFO_head >= I2C_RX_FIFO_SIZE) + rxFIFO_head = 0U; + } else + I2C_ReceiveData(I2C2); + break; + case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: + case I2C_EVENT_SLAVE_BYTE_TRANSMITTED: + if (txFIFO_level() > 0) { + I2C_SendData(I2C2, txFIFO[txFIFO_tail]); + txFIFO_tail++; + if (txFIFO_tail >= I2C_TX_FIFO_SIZE) + txFIFO_tail = 0U; + } else + I2C_SendData(I2C2, 0U); + break; + case I2C_EVENT_SLAVE_STOP_DETECTED: + I2C2_ClearFlag(); + break; + } +} + +void CI2CHost::I2C2_ClearFlag(void) { + // Clear ADDR flag + while((I2C2->SR1 & I2C_SR1_ADDR) == I2C_SR1_ADDR) { + I2C2->SR1; + I2C2->SR2; + } + + // Clear STOPF flag + while((I2C2->SR1 & I2C_SR1_STOPF) == I2C_SR1_STOPF) { + I2C2->SR1; + I2C2->CR1 |= 0x1; + } +} + +uint16_t CI2CHost::txFIFO_level(void) +{ + uint32_t tail = txFIFO_tail; + uint32_t head = txFIFO_head; + + if (tail > head) + return I2C_TX_FIFO_SIZE + head - tail; + else + return head - tail; +} + +uint16_t CI2CHost::rxFIFO_level(void) +{ + uint32_t tail = rxFIFO_tail; + uint32_t head = rxFIFO_head; + + if (tail > head) + return I2C_RX_FIFO_SIZE + head - tail; + else + return head - tail; +} + + +uint8_t CI2CHost::txFIFO_put(uint8_t next) +{ + if (txFIFO_level() < I2C_TX_FIFO_SIZE) { + txFIFO[txFIFO_head] = next; + + txFIFO_head++; + if (txFIFO_head >= I2C_TX_FIFO_SIZE) + txFIFO_head = 0U; + return 1U; + } else { + return 0U; + } +} + +uint8_t CI2CHost::AvailI2C(void) +{ + if (rxFIFO_level() > 0U) + return 1U; + else + return 0U; +} + + +uint8_t CI2CHost::ReadI2C(void) +{ + uint8_t data_c = rxFIFO[rxFIFO_tail]; + + rxFIFO_tail++; + if (rxFIFO_tail >= I2C_RX_FIFO_SIZE) + rxFIFO_tail = 0U; + + return data_c; +} + +void CI2CHost::WriteI2C(const uint8_t* data, uint16_t length) +{ + for (uint16_t i = 0U; i < length; i++) + txFIFO_put(data[i]); +} + +#endif \ No newline at end of file diff --git a/I2CHost.h b/I2CHost.h new file mode 100644 index 0000000..cb168ed --- /dev/null +++ b/I2CHost.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2019 by Andy Uribe CA6JAU + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if !defined(I2CHost_H) +#define I2CHost_H + +#include "Config.h" + +#if defined(STM32_I2C_HOST) + +#define I2C_CLK_FREQ 100000U +#define I2C_TX_FIFO_SIZE 512U +#define I2C_RX_FIFO_SIZE 512U + +class CI2CHost { +public: + CI2CHost(); + + void Init(void); + void I2C_EVHandler(void); + uint8_t AvailI2C(void); + uint8_t ReadI2C(void); + void WriteI2C(const uint8_t* data, uint16_t length); + +private: + void I2C2_ClearFlag(void); + uint16_t txFIFO_level(void); + uint16_t rxFIFO_level(void); + uint8_t txFIFO_put(uint8_t next); + + volatile uint8_t txFIFO[I2C_TX_FIFO_SIZE]; + volatile uint8_t rxFIFO[I2C_RX_FIFO_SIZE]; + volatile uint16_t txFIFO_head, txFIFO_tail; + volatile uint16_t rxFIFO_head, rxFIFO_tail; + +}; + +#endif + +#endif diff --git a/MMDVM_HS.cpp b/MMDVM_HS.cpp index f97a3be..cd61683 100644 --- a/MMDVM_HS.cpp +++ b/MMDVM_HS.cpp @@ -86,6 +86,10 @@ CCWIdTX cwIdTX; CSerialPort serial; CIO io; +#if defined(STM32_I2C_HOST) +CI2CHost i2c; +#endif + void setup() { serial.start(); diff --git a/STM32F10X_Lib b/STM32F10X_Lib index 2cf6b77..1debc23 160000 --- a/STM32F10X_Lib +++ b/STM32F10X_Lib @@ -1 +1 @@ -Subproject commit 2cf6b7712637a7961d52e0deee5f9b257bb9b9be +Subproject commit 1debc23063f3942608e2bd62d04d5e1249c47fa3 diff --git a/SerialSTM.cpp b/SerialSTM.cpp index 4363039..aae4117 100644 --- a/SerialSTM.cpp +++ b/SerialSTM.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2016 by Jim McLaughlin KI6ZUM - * Copyright (C) 2016,2017 by Andy Uribe CA6JAU + * Copyright (C) 2016,2017,2018,2019 by Andy Uribe CA6JAU * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include "Globals.h" #include "SerialPort.h" +#include "I2CHost.h" #if defined(STM32_USB_HOST) #include @@ -32,9 +33,9 @@ Pin definitions: - Host communication: -USART1 - TXD PA9 - RXD PA10 -or -USB VCOM +1) USART1 - TXD PA9 - RXD PA10 +2) USB VCOM +3) I2C - SCL PB10 - SDA PB11 - Serial repeater USART2 - TXD PA2 - RXD PA3 @@ -441,6 +442,8 @@ void CSerialPort::beginInt(uint8_t n, int speed) InitUSART1(speed); #elif defined(STM32_USB_HOST) usbserial.begin(); + #elif defined(STM32_I2C_HOST) + i2c.Init(); #endif break; case 3U: @@ -452,7 +455,7 @@ void CSerialPort::beginInt(uint8_t n, int speed) break; default: break; - } + } } int CSerialPort::availableInt(uint8_t n) @@ -463,6 +466,8 @@ int CSerialPort::availableInt(uint8_t n) return AvailUSART1(); #elif defined(STM32_USB_HOST) return usbserial.available(); + #elif defined(STM32_I2C_HOST) + return i2c.AvailI2C(); #endif case 3U: #if defined(SERIAL_REPEATER) @@ -483,6 +488,8 @@ uint8_t CSerialPort::readInt(uint8_t n) return ReadUSART1(); #elif defined(STM32_USB_HOST) return usbserial.read(); + #elif defined(STM32_I2C_HOST) + return i2c.ReadI2C(); #endif case 3U: #if defined(SERIAL_REPEATER) @@ -501,12 +508,14 @@ void CSerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool case 1U: #if defined(STM32_USART1_HOST) WriteUSART1(data, length); - if (flush) - TXSerialFlush1(); + if (flush) + TXSerialFlush1(); #elif defined(STM32_USB_HOST) usbserial.write(data, length); if (flush) usbserial.flush(); + #elif defined(STM32_I2C_HOST) + i2c.WriteI2C(data, length); #endif break; case 3U: