ready to alpha

подготовка к альфа-тестированию
This commit is contained in:
khristolyubov committed 2024-08-19 22:44:04 +07:00
commit e36b851783
164 files changed
+27352

No files matched your search

+122
View File
@@ -0,0 +1,122 @@
#include "Wire.h"
#include "time.h"
// 7-bit RTC address on the I2C bus, specified in the datasheet
#define RTC_ADDR 0x68
#define RTC_DATA_SIZE 7
// Specify 1 to set a new time at initialization
#define RTC_SET_NEW_TIME 0
uint8_t rxBytes[15];
struct tm newTime;
char str[32];
void setup()
{
Serial.begin(115200);
Serial.println("Start I2C rtc");
// Initializing the device as a master on the I2C bus
Wire.begin();
// Set new time if necessary
if (RTC_SET_NEW_TIME)
writeTimeToRtc(); // setting time is written inside the function
}
void loop()
{
// Read and display the current time
readTimeFromRtc();
delay(2000);
}
// ------------------- rtc ------------------- //
// Function to write new time to rtc
void writeTimeToRtc(void)
{
/* The data to be written is located in the common buffer.
First, the register address is specified - writing starts from register 0x00.
Next, the values ​​of seconds, minutes, etc. are listed in accordance with the
order of the corresponding registers, specified in the datasheet for ds1307.
The values ​​are pre-translated into binary-decimal format
*/
// sec min hour wday mday month year
uint8_t buf[] = {0x00, dec2bcd(00), dec2bcd(01), dec2bcd(12), dec2bcd(2), dec2bcd(1), dec2bcd(1), dec2bcd(24)};
Wire.beginTransmission(RTC_ADDR); // Start of transaction
Wire.write(buf, sizeof(buf)); // Writing data for a transaction
uint8_t result = Wire.endTransmission(); // Completing a transaction
// Show results
if (result == 0)
Serial.println("New time successfully set");
else
Serial.println("New time set failed");
}
// Function to read time from rtc
void readTimeFromRtc(void)
{
/* Send a request to receive data from rtc. When reading from rtc, you must
first specify from which register to start reading. To do this, use the extended
version of the requestFrom() function. In the arguments specify:
- device address,
- the number of bytes we want to read,
- the address of the starting register,
- the size of the address of the starting register in bytes,
- 1 - generate a stop condition after the request, 0 - do not generate
*/
Wire.requestFrom(RTC_ADDR, RTC_DATA_SIZE, 0x00, 1, 1);
// Get data
uint8_t i = 0;
while(Wire.available())
rxBytes[i++] = Wire.read();
// Show new time in the port upon successful reading
if (i == RTC_DATA_SIZE)
parseAndShowTime();
else
Serial.println("New time read failed");
}
// Functions for converting binary-decimal code to decimal and back
uint8_t bcd2dec(uint8_t val)
{
return (val >> 4) * 10 + (val & 0x0f);
}
uint8_t dec2bcd(uint8_t val)
{
return ((val / 10) << 4) + (val % 10);
}
// Function for format and output the current time to the port
void parseAndShowTime(void)
{
/* take the values ​​for time output from the received data buffer.
Convert the values ​​into decimal format and adjust them in accordance with
the datasheet for ds1307
*/
newTime.tm_sec = bcd2dec(rxBytes[0] & 0x7f);
newTime.tm_min = bcd2dec(rxBytes[1]);
if (rxBytes[2] & (1 << 6))
{
// RTC in 12 hour mode
newTime.tm_hour = bcd2dec(rxBytes[2] & 0x1f) - 1;
if (rxBytes[2] & (1 << 5))
newTime.tm_hour += 12;
}
else
newTime.tm_hour = bcd2dec(rxBytes[2] & 0x3f);
newTime.tm_wday = bcd2dec(rxBytes[3])-1;
newTime.tm_mday = bcd2dec(rxBytes[4]);
newTime.tm_mon = bcd2dec(rxBytes[5])-1;
// Subtract 1900 so that the year is correctly displayed in the struct tm type structure
newTime.tm_year = bcd2dec(rxBytes[6])+2000-1900;
// The received time is output to the port in the format Sun Aug 19 02:56:02 2012
strftime(str, sizeof(str), "%c", &newTime);
Serial.println(str);
}
@@ -0,0 +1,92 @@
// I2C master
#include <Wire.h>
// Slave address
uint8_t SLAVE_ADDRESS = 0x33;
// Buffers for sending and receiving
uint8_t masterTxData[3] = {0x30, 0x41, 0x51};
uint8_t masterRxData[4] = {0};
// Function for sending data via I2C bus
uint8_t masterSendData(uint8_t* data, uint8_t dataLen)
{
// Initiating work with the bus
Wire.beginTransmission(SLAVE_ADDRESS);
// Send data
Wire.write(data, dataLen);
// Finish working with the bus and return the result
return Wire.endTransmission();
}
// Function to receive a specified number of bytes from the I2C bus
uint8_t masterGetData(uint8_t *buf, uint8_t dataSize)
{
// Request data
Wire.requestFrom(SLAVE_ADDRESS, dataSize);
// If there are bytes available for reading, read them in a loop
uint8_t n = 0;
while (Wire.available())
{
// reading from the bus - from the slave device
buf[n] = Wire.read();
// Increasing the number of received bytes
n++;
}
// Return the number of received bytes
return n;
}
// -------------------------------------------- //
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println("I2C master start");
// Initialize the device on the I2C bus as a master
Wire.begin();
Wire.setClock(400000);
}
void loop()
{
// Send data to slave
Serial.println("------------------------");
Serial.println("Master | Sending 3 bytes");
uint8_t result = masterSendData(masterTxData, sizeof(masterTxData));
// Show result
if (result == 0)
Serial.println("Master | Bytes sended");
else
{
Serial.print("Master | Send ERROR! Code: ");
Serial.println(result);
}
// Change the first byte for variety
masterTxData[0] += 1;
// Delay before requesting data
delay(2000);
// Request data from the slave
Serial.println("------------------------");
Serial.println("Master | Receiving 4 bytes");
uint8_t bytesQty = masterGetData(masterRxData, sizeof(masterRxData));
// Show result
if (bytesQty == 0)
Serial.println("Master | Receive ERROR!");
else
{
for (uint8_t i = 0; i < bytesQty; i++)
{
Serial.print("Master | Received byte: 0x");
Serial.println(masterRxData[i], HEX);
}
}
// Delay before sending data
delay(2000);
}
@@ -0,0 +1,48 @@
// i2c_scanner
#include <Wire.h>
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println("I2C scanner start");
Wire.begin();
}
void loop()
{
int devicesQty = 0;
Serial.println("Scanning...");
for (byte address = 1; address < 127; address++)
{
// transmitting address to I2C bus
Wire.beginTransmission(address);
byte error = Wire.endTransmission();
// Wire.endTransmission() will return 0 only if an ACK is received
// from the subscriber with the current address
if (error == 0)
{
Serial.print("Device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
devicesQty++;
}
delayMicroseconds(1);
}
if (devicesQty == 0)
Serial.println("No device found");
else
{
Serial.print(devicesQty);
Serial.println(" devices found");
}
Serial.println();
delay(5000);
}
@@ -0,0 +1,91 @@
// I2C slave
#include <Wire.h>
// The address on the I2C bus that we will assign to this device
constexpr int MY_ADDRESS = 0x33;
// Buffers for sending and receiving
uint8_t slaveTxData[4] = {0x00, 0x10, 0x22, 0x84};
uint8_t slaveRxData[8] = {0};
// Function for receiving data from the I2C bus
uint8_t slaveGetData(uint8_t *buf, uint8_t bufSize)
{
// If there are bytes available for reading, read them in a loop
uint8_t n = 0;
while (Wire.available())
{
// Read from the bus - from the master device
buf[n] = Wire.read();
// If the entire buffer is filled, stop reading
if (++n == bufSize)
break;
}
// Return the number of received bytes
return n;
}
// Function for sending data via I2C bus
uint8_t slaveSendData(uint8_t* data, uint8_t dataLen)
{
return Wire.write(data, dataLen);
}
// A function that will be called if the master requests data
void requestEvent()
{
Serial.println("------------------------");
Serial.println("Slave | Request event");
// Send data
uint8_t txBytesQty = slaveSendData(slaveTxData, sizeof(slaveTxData));
// Show result
if (txBytesQty == sizeof(slaveTxData))
Serial.print("Slave | Bytes quantity sent: ");
else
Serial.print("Slave | Send ERROR! Bytes quantity sent: ");
Serial.println(txBytesQty);
slaveTxData[0] += 1; // Change the first byte for variety
}
// Function that will be called if the master sends data
void receiveEvent(int bytesNum)
{
Serial.println("------------------------");
Serial.println("Slave | Receive event");
// Get new data
uint8_t rxBytesQty = slaveGetData(slaveRxData, sizeof(slaveRxData));
// Show result
if (rxBytesQty == 0)
Serial.println("Slave | Receive ERROR!");
else
{
for (uint8_t i = 0; i < rxBytesQty; i++)
{
Serial.print("Slave | Received byte: 0x");
Serial.println(slaveRxData[i], HEX);
}
}
}
// ----------------------------------------- //
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println("I2C slave start");
// Start working with I2C as a slave device with the address MY_ADDRESS
Wire.begin(MY_ADDRESS);
// Register an event handler that will be called when data is requested by the master device
Wire.onRequest(requestEvent);
// Register an event handler that will be called after receiving data from the master device
Wire.onReceive(receiveEvent);
}
void loop()
{
// Don't do anything in the loop, everything is implemented in the registered event handlers
}
+29
View File
@@ -0,0 +1,29 @@
#######################################
# Syntax Coloring Map For Wire
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
setClock KEYWORD2
beginTransmission KEYWORD2
endTransmission KEYWORD2
requestFrom KEYWORD2
onReceive KEYWORD2
onRequest KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
Wire KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
+9
View File
@@ -0,0 +1,9 @@
name=Wire
version=0.0.0
author=Arduino
maintainer=Elron
sentence=Allows the communication between devices or sensors connected via Two Wire (I2C) Interface Bus.
paragraph=
category=Communication
url=http://www.arduino.cc/en/Reference/Wire
architectures=MIK32_Amur
+318
View File
@@ -0,0 +1,318 @@
extern "C"
{
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "utility/twi.h"
}
#include "Wire.h"
// Initialize Class Variables
uint8_t TwoWire::rxBuffer[BUFFER_LENGTH];
uint8_t TwoWire::rxBufferIndex = 0;
uint8_t TwoWire::rxBufferLength = 0;
uint8_t TwoWire::txAddress = 0; // 7 bits without shift
uint8_t TwoWire::txBuffer[BUFFER_LENGTH];
uint8_t TwoWire::txBufferIndex = 0;
uint8_t TwoWire::txBufferLength = 0;
uint8_t TwoWire::transmitting = 0;
uint8_t TwoWire::slaveAddress = 0; // 7 bits without shift in slave mode
void (*TwoWire::user_onRequest)(void);
void (*TwoWire::user_onReceive)(int);
// Constructors
TwoWire::TwoWire()
{
}
// --------------------------- Public Methods --------------------------- //
void TwoWire::begin(void)
{
rxBufferIndex = 0;
rxBufferLength = 0;
txBufferIndex = 0;
txBufferLength = 0;
twi_init(slaveAddress);
twi_attachSlaveTxEvent(onRequestService); // default callback must exist
twi_attachSlaveRxEvent(onReceiveService); // default callback must exist
}
void TwoWire::begin(uint8_t address)
{
slaveAddress = address;
begin();
}
void TwoWire::begin(int address)
{
begin((uint8_t)address);
}
void TwoWire::end(void)
{
flush(); // wait for transmission complete
twi_deinit();
slaveAddress = 0;
}
void TwoWire::setClock(uint32_t clock)
{
if (twi_setFrequency(clock, false) != I2C_OK)
ErrorMsgHandler("Wire.setClock(): invalid frequency or Wire was not begin");
}
// ----------------------------- request ----------------------------- //
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop)
{
if (isize > 0)
{
// send internal register address if needed
beginTransmission(address); // save slave address
// the maximum size of internal address is 3 bytes
if (isize > 3) isize = 3;
// write internal register address - most significant byte first
while (isize-- > 0)
write((uint8_t)(iaddress >> (isize*8))); // write data to txBuf
endTransmission(false); // transmit data without stop generation
}
// clamp to buffer length
if(quantity > BUFFER_LENGTH)
quantity = BUFFER_LENGTH;
// perform blocking read into buffer
uint8_t read = twi_masterReadFrom(address, rxBuffer, quantity, sendStop);
// set rx buffer iterator vars
rxBufferIndex = 0;
rxBufferLength = read;
return read;
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
{
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, (uint8_t)0, (uint8_t)sendStop);
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
{
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
}
uint8_t TwoWire::requestFrom(int address, int quantity)
{
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
}
uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)
{
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop);
}
// ----------------------------- Transmission ----------------------------- //
void TwoWire::beginTransmission(uint8_t address)
{
// indicate that we are transmitting
transmitting = 1;
// set address of targeted slave whithout shift
txAddress = address;
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
}
void TwoWire::beginTransmission(int address)
{
beginTransmission((uint8_t)address);
}
// Calling endTransmission(false) allows a sketch to
// perform a repeated start.
// WARNING: Nothing in the library keeps track of whether
// the bus tenure has been properly ended with a STOP. It
// is very possible to leave the bus in a hung state if
// no call to endTransmission(true) is made. Some I2C
// devices will behave oddly if they do not see a STOP.
uint8_t TwoWire::endTransmission(uint8_t sendStop)
{
uint8_t ret = I2C_ERROR;
if (transmitting)
{
// transmit buffer (blocking)
ret = twi_masterWriteTo(txAddress, txBuffer, txBufferLength, sendStop);
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
// indicate that we are done transmitting
transmitting = 0;
}
return ret;
}
// This provides backwards compatibility with the original
// definition, and expected behaviour, of endTransmission
uint8_t TwoWire::endTransmission(void)
{
return endTransmission((uint8_t)true);
}
// ----------------------------- Write ----------------------------- //
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
size_t TwoWire::write(uint8_t data)
{
size_t ret = 1;
if (transmitting)
{
// in master transmitter mode
// don't bother if buffer is full
if(txBufferLength >= BUFFER_LENGTH)
{
setWriteError();
return 0;
}
// put byte in tx buffer
txBuffer[txBufferIndex] = data;
++txBufferIndex;
// update amount in buffer
txBufferLength = txBufferIndex;
}
else
{
// in slave send mode - reply to master
if (twi_slaveWrite(&data, 1) != I2C_OK)
ret = 0;
}
return ret;
}
/**
* @brief This function must be called in slave Tx event callback or after
* beginTransmission() and before endTransmission().
* @param pdata: pointer to the buffer data
* @param quantity: number of bytes to write
* @retval number of bytes ready to write.
*/
size_t TwoWire::write(const uint8_t *data, size_t quantity)
{
size_t ret = quantity;
if (transmitting)
{
// in master transmitter mode
for(size_t i = 0; i < quantity; ++i)
write(data[i]);
}
else
{
// in slave send mode - reply to master
if (twi_slaveWrite((uint8_t *)data, quantity) != I2C_OK)
ret = 0;
}
return ret;
}
// ----------------------------- Stream func ----------------------------- //
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
int TwoWire::available(void)
{
return rxBufferLength - rxBufferIndex;
}
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
int TwoWire::read(void)
{
int value = -1;
// get each successive byte on each call
if (rxBufferIndex < rxBufferLength)
{
value = rxBuffer[rxBufferIndex];
++rxBufferIndex;
}
return value;
}
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
int TwoWire::peek(void)
{
int value = -1;
if (rxBufferIndex < rxBufferLength)
value = rxBuffer[rxBufferIndex];
return value;
}
void TwoWire::flush(void)
{
// we use blocking transactions, so we won't get here until the reception/transmission is complete
rxBufferIndex = 0;
rxBufferLength = 0;
txBufferIndex = 0;
txBufferLength = 0;
txAddress = 0;
}
// ----------------------------- Events ----------------------------- //
// behind the scenes function that is called when data is received
void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes)
{
// don't bother if user hasn't registered a callback
if(!user_onReceive)
return;
// copy twi rx buffer into local read buffer
// this enables new reads to happen in parallel
memcpy(rxBuffer, inBytes, numBytes);
// set rx iterator vars
rxBufferIndex = 0;
rxBufferLength = numBytes;
// alert user program
user_onReceive(numBytes);
}
// behind the scenes function that is called when data is requested
void TwoWire::onRequestService(void)
{
// don't bother if user hasn't registered a callback
if(user_onRequest)
user_onRequest(); // alert user program
}
// sets function called on slave write
void TwoWire::onReceive( void (*function)(int) )
{
user_onReceive = function;
}
// sets function called on slave read
void TwoWire::onRequest( void (*function)(void) )
{
user_onRequest = function;
}
// С function for trap handler
extern "C" void wire_handler_wrapper(void)
{
twi_interruptHandler();
}
// ----------------------------- Preinstantiate Objects ----------------------------- //
TwoWire Wire = TwoWire( );
+69
View File
@@ -0,0 +1,69 @@
#ifndef TwoWire_h
#define TwoWire_h
#include "Stream.h"
#include "Arduino.h"
#define BUFFER_LENGTH 32
// WIRE_HAS_END means Wire has end()
#define WIRE_HAS_END 1
class TwoWire : public Stream
{
private:
static uint8_t rxBuffer[];
static uint8_t rxBufferIndex;
static uint8_t rxBufferLength;
static uint8_t txAddress;
static uint8_t txBuffer[];
static uint8_t txBufferIndex;
static uint8_t txBufferLength;
static uint8_t transmitting;
static uint8_t slaveAddress;
static void (*user_onRequest)(void);
static void (*user_onReceive)(int numBytes);
static void onRequestService(void);
static void onReceiveService(uint8_t* inBytes, int numBytes);
public:
TwoWire();
void begin();
void begin(uint8_t);
void begin(int);
void end();
void setClock(uint32_t frequency);
void beginTransmission(uint8_t address);
void beginTransmission(int address);
uint8_t endTransmission(void);
uint8_t endTransmission(uint8_t sendStop);
uint8_t requestFrom(uint8_t address, uint8_t quantity);
uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop);
uint8_t requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop);
uint8_t requestFrom(int address, int quantity);
uint8_t requestFrom(int address, int quantity, int sendStop);
virtual int available(void);
virtual int read(void);
virtual int peek(void);
virtual void flush(void);
virtual size_t write(uint8_t data);
virtual size_t write(const uint8_t * data, size_t quantity);
inline size_t write(unsigned long n) { return write((uint8_t)n); }
inline size_t write(long n) { return write((uint8_t)n); }
inline size_t write(unsigned int n) { return write((uint8_t)n); }
inline size_t write(int n) { return write((uint8_t)n); }
using Print::write;
void onReceive( void (*)(int) );
void onRequest( void (*)(void) );
};
extern TwoWire Wire;
#endif
+384
View File
@@ -0,0 +1,384 @@
#include <stdlib.h>
#include <inttypes.h>
#include "Arduino.h"
#include "twi.h"
#include "mik32_hal_i2c.h"
#include "mik32_hal_irq.h"
#define TIMEOUT_TICKS 1000000
#define TWI_FREQ_DEF WIRE_FREQ_100K // default is 100 kHz
static void (*twi_onSlaveTransmit)(void);
static void (*twi_onSlaveReceive)(uint8_t*, int);
static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
static volatile uint8_t twi_rxBufferIndex;
I2C_HandleTypeDef hi2c;
static uint32_t CurrentFrequency = TWI_FREQ_DEF;
static bool twiIsOn = false;
// ---------------------------------------------------------------- //
/*
* Function twi_init
* Desc readys twi pins and sets twi bitrate
* Input slaveAddress - address of Arduino if working in slave mode
* Output none
*/
uint8_t twi_init(uint8_t slaveAddress)
{
// Common settings
uint32_t EPICmask;
#if I2C_NUM == 0
hi2c.Instance = I2C_0;
EPICmask = HAL_EPIC_I2C_0_MASK;
#elif I2C_NUM == 1
hi2c.Instance = I2C_1;
EPICmask = HAL_EPIC_I2C_1_MASK;
#else
#error "Unsupported I2C_NUM value in pins_arduino.h"
#endif
hi2c.Init.DigitalFilter = I2C_DIGITALFILTER_2CLOCKCYCLES;
hi2c.Init.AnalogFilter = I2C_ANALOGFILTER_DISABLE;
if (slaveAddress == 0) // if there is no address - master mode
{
hi2c.Init.Mode = HAL_I2C_MODE_MASTER;
hi2c.Init.AutoEnd = I2C_AUTOEND_ENABLE;
}
else
{
// 7-bit address without any additional bits
hi2c.Init.Mode = HAL_I2C_MODE_SLAVE;
hi2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // stretch is used
hi2c.Init.OwnAddress1 = slaveAddress;
}
// set the frequency
if (hi2c.Init.Mode == HAL_I2C_MODE_MASTER)
twi_setFrequency(CurrentFrequency, true);
else
twi_setFrequency(0, true);
if (HAL_I2C_Init(&hi2c) != HAL_OK)
return I2C_ERROR;
// enable interrupts for slave mode
if (hi2c.Init.Mode == HAL_I2C_MODE_SLAVE)
{
// enable interrupts for addressing, byte reception and transfer completion
HAL_I2C_InterruptDisable(&hi2c, I2C_INTMASK);
HAL_I2C_InterruptEnable(&hi2c, I2C_CR1_ADDRIE_M | I2C_CR1_RXIE_M | I2C_CR1_STOPIE_M);
// enable interrupt from i2c
HAL_EPIC_MaskLevelSet(EPICmask);
}
twiIsOn = true;
return I2C_OK;
}
/*
* Function twi_deinit
* Desc disables twi pins
* Input none
* Output none
*/
void twi_deinit(void)
{
uint32_t EPICmask;
HAL_I2C_Disable(&hi2c);
// disable clock
#if I2C_NUM == 0
hi2c.Instance = I2C_0;
EPICmask = HAL_EPIC_I2C_0_MASK;
__HAL_PCC_I2C_0_CLK_DISABLE();
#elif I2C_NUM == 1
hi2c.Instance = I2C_1;
EPICmask = HAL_EPIC_I2C_1_MASK;
__HAL_PCC_I2C_1_CLK_DISABLE();
#else
#error "Unsupported I2C_NUM value in pins_arduino.h"
#endif
// for slave mode disable interrupts from i2c
if (hi2c.Init.Mode == HAL_I2C_MODE_SLAVE)
HAL_EPIC_MaskLevelClear(EPICmask);
// reconfigure pins to z state
GPIO_InitTypeDef GPIO_InitStruct;
memset(&GPIO_InitStruct, 0, sizeof(GPIO_InitStruct));
// SDA
GPIO_InitStruct.Pin = (HAL_PinsTypeDef)digitalPinToBitMask(PIN_WIRE_SDA);
GPIO_InitStruct.Mode = HAL_GPIO_MODE_GPIO_INPUT;
GPIO_InitStruct.Pull = HAL_GPIO_PULL_NONE;
HAL_GPIO_Init(digitalPinToPort(PIN_WIRE_SDA), &GPIO_InitStruct);
// SCL
GPIO_InitStruct.Pin = (HAL_PinsTypeDef)digitalPinToBitMask(PIN_WIRE_SCL);
HAL_GPIO_Init(digitalPinToPort(PIN_WIRE_SCL), &GPIO_InitStruct);
twiIsOn = false;
}
/*
* Function twi_setClock
* Desc sets twi bit rate
* Input Clock Frequency - 100000 / 400000 / 1000000,
* onInit = true only if function is called from twi_init()
* Output I2C_OK - frequency changed, I2C_ERROR - frequency didn't change
*/
uint8_t twi_setFrequency(uint32_t frequency, bool onInit)
{
uint8_t ret = I2C_OK;
// change the frequency only during or after bus initialization
if (twiIsOn || onInit)
{
// You can change the frequency only when the interface is turned off
HAL_I2C_Disable(&hi2c);
if (frequency == WIRE_FREQ_100K) // 100 kHz
{
hi2c.Clock.PRESC = 2;
hi2c.Clock.SCLDEL = 8;
hi2c.Clock.SDADEL = 2;
hi2c.Clock.SCLH = 49;
hi2c.Clock.SCLL = 49;
CurrentFrequency = WIRE_FREQ_100K;
}
else if (frequency == WIRE_FREQ_400K) // 400 kHz
{
hi2c.Clock.PRESC = 0;
hi2c.Clock.SCLDEL = 3;
hi2c.Clock.SDADEL = 2;
hi2c.Clock.SCLH = 30;
hi2c.Clock.SCLL = 30;
CurrentFrequency = WIRE_FREQ_400K;
}
else if (frequency == WIRE_FREQ_1000K)// 1000 kHz
{
hi2c.Clock.PRESC = 0;
hi2c.Clock.SCLDEL = 1;
hi2c.Clock.SDADEL = 2;
hi2c.Clock.SCLH = 6;
hi2c.Clock.SCLL = 6;
CurrentFrequency = WIRE_FREQ_1000K;
}
else if (frequency == 0) // slave mode
{
hi2c.Clock.PRESC = 0;
hi2c.Clock.SCLDEL = 0;
hi2c.Clock.SDADEL = 2;
hi2c.Clock.SCLH = 0;
hi2c.Clock.SCLL = 0;
}
else
// frequency does not change
ret = I2C_ERROR;
// write the timings to the register if everything is OK
if (ret == I2C_OK)
HAL_I2C_SetClockSpeed(&hi2c);
//turn the interface back only if initialization has already passed
if (twiIsOn)
HAL_I2C_Enable(&hi2c);
}
else
ret = I2C_ERROR;
return ret;
}
/*
* Function twi_masterReadFrom
* Desc attempts to become twi bus master and read a
* series of bytes from a device on the bus
* Input address: 7bit i2c device address
* data: pointer to byte array
* length: number of bytes to read into array
* sendStop: Boolean indicating whether to send a stop at the end
* Output number of bytes read
*/
uint8_t twi_masterReadFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
{
uint8_t ret = 0;
// if there are errors left from previous transactions, you need to restart
// the interface for correct operation
if (hi2c.ErrorCode != I2C_ERROR_NONE)
HAL_I2C_Reset(&hi2c);
if (sendStop) hi2c.Init.AutoEnd = 1;
else hi2c.Init.AutoEnd = 0;
// put the data directly into the external buffer
if (HAL_I2C_Master_Receive(&hi2c, address, data, length, TIMEOUT_TICKS) == HAL_OK)
ret = length;
return ret;
}
/*
* Function twi_masterWriteTo
* Desc attempts to become twi bus master and write a
* series of bytes to a device on the bus
* Input address: 7bit i2c device address
* data: pointer to byte array
* length: number of bytes in array
* sendStop: boolean indicating whether or not to send a stop at the end
* Output 0 .. success
* 1 .. length to long for buffer
* 2 .. address send, NACK received
* 3 .. data send, NACK received
* 4 .. other twi error (lost bus arbitration, bus error, ..)
* 5 .. timeout
*/
uint8_t twi_masterWriteTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
{
uint8_t ret = I2C_OK;
// if there are errors left from previous transactions, you need to restart
// the interface for correct operation
if (hi2c.ErrorCode != I2C_ERROR_NONE)
HAL_I2C_Reset(&hi2c);
if (sendStop) hi2c.Init.AutoEnd = 1;
else hi2c.Init.AutoEnd = 0;
// take data from an external buffer
HAL_I2C_Master_Transmit(&hi2c, address, data, length, TIMEOUT_TICKS);
// parse errors
// check separately, because in hal libraries not all functions look at this
if (hi2c.Instance->ISR & I2C_ISR_NACKF_M)
hi2c.ErrorCode = I2C_ERROR_NACK;
if (hi2c.ErrorCode == (HAL_I2C_ErrorTypeDef)I2C_ERROR_TIMEOUT) ret = I2C_TIMEOUT; // timeout
else if (hi2c.ErrorCode == (HAL_I2C_ErrorTypeDef)I2C_ERROR_NACK) ret = I2C_NACK_DATA; // didn't receive ACK
else if (hi2c.ErrorCode != (HAL_I2C_ErrorTypeDef)I2C_OK) ret = I2C_ERROR; // any other error
return ret;
}
/*
* Function twi_slaveWrite
* Desc attempts to become twi bus slave and write a
* series of bytes to a master after it asks
* Input txData: pointer to byte array
* bytesNum: number of bytes in array
* Output 0 .. success
* 5 .. timeout
*/
i2c_status_e twi_slaveWrite(uint8_t *txData, uint8_t bytesNum)
{
if ((hi2c.ErrorCode != I2C_ERROR_NONE))
HAL_I2C_Reset(&hi2c);
// отправка данных
HAL_StatusTypeDef error_code = HAL_OK;
hi2c.Instance->CR2 &= ~I2C_CR2_RELOAD_M;
if (!(hi2c.Instance->CR1 & I2C_CR1_NOSTRETCH_M)) // NOSTRETCH = 0
hi2c.Instance->ISR |= I2C_ISR_TXE_M; // Reset TXDR contents
hi2c.Instance->TXDR = txData[0]; // The first recording is made in advance
// Запись байта
for (uint32_t tx_count = 1; tx_count < bytesNum; tx_count++)
{
if ((error_code = HAL_I2C_Slave_WaitTXIS(&hi2c, TIMEOUT_TICKS)) != HAL_OK)
{
// неудачная запись
hi2c.Instance->ISR |= I2C_ISR_TXE_M; // Reset TXDR contents
hi2c.Instance->ICR |= I2C_ICR_STOPCF_M; // Clear the STOP detection flag on the bus
HAL_I2C_Reset(&hi2c);
return I2C_TIMEOUT;
}
hi2c.Instance->TXDR = txData[tx_count];
}
if ((error_code = HAL_I2C_WaitBusy(&hi2c, TIMEOUT_TICKS)) != HAL_OK)
{
// неудачное завершение транзакции
HAL_I2C_Reset(&hi2c);
return I2C_TIMEOUT;
}
hi2c.Instance->ISR |= I2C_ISR_TXE_M; // Reset TXDR contents
hi2c.Instance->ICR |= I2C_ICR_STOPCF_M; // Clear the STOP detection flag on the bus
return I2C_OK;
}
/*
* Function twi_attachSlaveRxEvent
* Desc sets function called before a slave read operation
* Input function: callback function to use
* Output none
*/
void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) )
{
twi_onSlaveReceive = function;
}
/*
* Function twi_attachSlaveTxEvent
* Desc sets function called before a slave write operation
* Input function: callback function to use
* Output none
*/
void twi_attachSlaveTxEvent( void (*function)(void) )
{
twi_onSlaveTransmit = function;
}
/*
* Function twi_interruptHandler
* Desc handles an interrupts from twi
* Input none
* Output none
*/
void twi_interruptHandler(void)
{
uint32_t int_mask = hi2c.Instance->CR1 & I2C_INTMASK; // interrupts allowed
uint32_t interrupt_status = hi2c.Instance->ISR; // current flags
// master calls by address, device in slave mode
if ((interrupt_status & I2C_ISR_ADDR_M) && (int_mask & I2C_CR1_ADDRIE_M))
{
// reset ADDR flag
hi2c.Instance->ICR |= I2C_ICR_ADDRCF_M;
// look at the transmission direction and respond to the request
if (interrupt_status & I2C_ISR_DIR_M) // master reads, slave sends
// отправляем данные
twi_onSlaveTransmit();
else // master writes, slave reads
{
twi_rxBufferIndex = 0; // write from the beginning of the buffer
hi2c.State = HAL_I2C_STATE_BUSY;
hi2c.Instance->CR2 &= ~I2C_CR2_RELOAD_M;
// wait for interrupts because of receiving a byte or a stop condition
}
}
// new byte of data received
if ((interrupt_status & I2C_ISR_RXNE_M) && (int_mask & I2C_CR1_RXIE_M))
{
// put new byte into buffer
twi_rxBuffer[twi_rxBufferIndex++] = (uint8_t)hi2c.Instance->RXDR;
}
// master sent a STOP to the bus
if ((interrupt_status & I2C_ISR_STOPF_M) && (int_mask & I2C_CR1_STOPIE_M))
{
hi2c.State = HAL_I2C_STATE_END;
hi2c.Instance->ISR |= I2C_ISR_TXE_M; // Reset TXDR contents
hi2c.Instance->ICR |= I2C_ICR_STOPCF_M; // Clear the STOP detection flag on the bus
// pass the received data to callback function
twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
}
}
+41
View File
@@ -0,0 +1,41 @@
#ifndef __TWI_H__
#define __TWI_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifndef TWI_BUFFER_LENGTH
#define TWI_BUFFER_LENGTH 32
#endif
// I2C state
typedef enum
{
I2C_OK = 0,
I2C_DATA_TOO_LONG = 1,
I2C_NACK_ADDR = 2,
I2C_NACK_DATA = 3,
I2C_ERROR = 4,
I2C_TIMEOUT = 5,
I2C_BUSY = 6
} i2c_status_e;
uint8_t twi_init(uint8_t slaveAddress);
void twi_deinit(void);
uint8_t twi_setFrequency(uint32_t frequency, bool onInit);
uint8_t twi_masterReadFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop);
uint8_t twi_masterWriteTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop);
i2c_status_e twi_slaveWrite(uint8_t *txData, uint8_t bytesNum);
void twi_attachSlaveRxEvent(void (*function)(uint8_t*, int));
void twi_attachSlaveTxEvent(void (*function)(void));
void twi_interruptHandler(void);
#ifdef __cplusplus
}
#endif
#endif /* __TWI_H__ */