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

@@ -0,0 +1,79 @@
/*
ADS1256 ADC is used for this test. Command for write
and read is taken from the datasheet.
*/
#include "SPI.h"
#define CS_PIN 9
// address of register to read and write
const int reg_to_test = 0x03;
uint8_t readVal = 0;
uint8_t writeVal = 0;
// read one register value
uint8_t ADC_read_register(uint8_t registerAddress)
{
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1));
digitalWrite(CS_PIN, LOW); // CS must stay LOW during the entire sequence
SPI.transfer(0x10 | registerAddress); // 0x10 = 0001000 = RREG - OR together the two numbers (command + address)
SPI.transfer(0x00); // 2nd empty command byte to read one byte
delayMicroseconds(5); // see t6 in the datasheet
uint8_t readVal = SPI.transfer(0xFF); // read out the register value
digitalWrite(CS_PIN, HIGH);
SPI.endTransaction();
return readVal;
}
// write one register value
void ADC_write_register(uint8_t registerAddress, uint8_t registerValueToWrite)
{
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1));
digitalWrite(CS_PIN, LOW); // CS must stay LOW during the entire sequence
delayMicroseconds(5); // see t6 in the datasheet
SPI.transfer(0x50 | registerAddress); // 0x50 = 01010000 = WREG
SPI.transfer(0x00); // 2nd empty command byte to write one byte
SPI.transfer(registerValueToWrite); // pass the value to the register
digitalWrite(CS_PIN, HIGH);
SPI.endTransaction();
}
// ----------------------------------------- //
void setup()
{
Serial.begin(115200);
Serial.println("Start spi test");
// init chip select pin
pinMode(CS_PIN, OUTPUT);
digitalWrite(CS_PIN, HIGH);
// init spi
SPI.begin();
delay(100);
// read initial register value
Serial.print("Initial register value: 0x");
Serial.println(ADC_read_register(reg_to_test), HEX);
}
void loop()
{
// write new reg value
ADC_write_register(reg_to_test, writeVal);
Serial.print("Write val: 0x");
Serial.println(writeVal, HEX);
// read updated reg value
readVal = ADC_read_register(reg_to_test);
Serial.print("Read val: 0x");
Serial.println(readVal, HEX);
// increase write value
writeVal++;
Serial.println("-------------");
// wait
delay(2000);
}
+37
View File
@@ -0,0 +1,37 @@
#######################################
# Syntax Coloring Map For SPI
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
SPI KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
beginTransaction KEYWORD2
end KEYWORD2
endTransaction KEYWORD2
transfer KEYWORD2
setBitOrder KEYWORD2
setDataMode KEYWORD2
setClockDivider KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
SPI_CLOCK_DIV4 LITERAL1
SPI_CLOCK_DIV8 LITERAL1
SPI_CLOCK_DIV16 LITERAL1
SPI_CLOCK_DIV32 LITERAL1
SPI_CLOCK_DIV64 LITERAL1
SPI_CLOCK_DIV128 LITERAL1
SPI_CLOCK_DIV256 LITERAL1
SPI_MODE0 LITERAL1
SPI_MODE1 LITERAL1
SPI_MODE2 LITERAL1
SPI_MODE3 LITERAL1
+10
View File
@@ -0,0 +1,10 @@
name=SPI
version=0.0.0
author=Arduino
maintainer=Elron
sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus.
paragraph=SPI is a synchronous serial data protocol used by microcontrollers for communicating with one or more peripheral devices quickly over short distances. It uses three lines common to all devices (MISO, MOSI and SCK) and one specific for each device.
category=Communication
url=http://www.arduino.cc/en/Reference/SPI
architectures=MIK32_Amur
+339
View File
@@ -0,0 +1,339 @@
#include "SPI.h"
#include "mik32_hal_spi.h"
SPI_HandleTypeDef hspi;
bool newConfig = false;
bool isInited = false;
uint32_t currentSpeed = 0;
int8_t currentDataOrder = -1;
int8_t currentDataMode = -1;
static uint8_t reverse_bits(uint8_t byte);
// ------------------------------------------------------------------ //
void SPISettings::spiUpdateSettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode)
{
// update config only if something has changed
if ((currentSpeed != speedMaximum) || (currentDataOrder != dataOrder) ||
(currentDataMode != dataMode))
{
// Find the fastest clock that is less than or equal to the
// given clock rate. If nothing is slow enough - use the slowest.
// mik32v2 has the set of deviders, that can be calculate as:
// div = 2 << (1...7). Value in braсkets is a value for config register
uint8_t divRegVal = 0; // start from minimal divider (maximum speed)
while(divRegVal < 7)
{
divRegVal++; // values from 1 to 7
if ((F_CPU/(2 << divRegVal)) <= speedMaximum)
// find suitable divider
break;
}
// if break didn't call in cycle, it will be the greatest divRegVal (and divider)
// update config
hspi.Instance = SPI_1;
hspi.Init.SPI_Mode = HAL_SPI_MODE_MASTER; // only master mode
hspi.Init.CLKPhase = dataMode & 0b00000001;
hspi.Init.CLKPolarity = (dataMode & 0b00000010)>>1;
hspi.Init.ThresholdTX = 4;
hspi.Init.BaudRateDiv = divRegVal;
hspi.Init.Decoder = SPI_DECODER_NONE;
hspi.Init.ManualCS = SPI_MANUALCS_ON;
hspi.Init.ChipSelect = SPI_CS_NONE;
currentSpeed = speedMaximum;
currentDataOrder = dataOrder;
currentDataMode = dataMode;
newConfig = true;
}
}
// ------------------------------------------------------------------ //
// pins shift in gpio register
#define PIN_1_3_GPIO_S 3
#define PIN_1_4_GPIO_S 4
SPIClass SPI;
bool SPIClass::spiInUse = false;
uint8_t SPIClass::interruptMode = 0;
uint8_t SPIClass::interruptMask = 0;
void SPIClass::begin()
{
// there is a seller on pin 1.6 which replace D10 from spi NSS pin 1.3 to pin 1.4,
// because spi needs pin 1.3 for correct work
// replace config from 1.3 to 1.4
uint8_t config = ((PAD_CONFIG->PORT_1_CFG) & (0b11<<(2*PIN_1_3_GPIO_S))) >> (2*PIN_1_3_GPIO_S);
if (config == 0) // common gpio
{
// pin direction
uint8_t direction = ((GPIO_1->DIRECTION_IN) & (1<<PIN_1_3_GPIO_S)) >> PIN_1_3_GPIO_S;
if (direction == 1) // input
GPIO_1->DIRECTION_IN |= (1<<PIN_1_4_GPIO_S);
else // output
GPIO_1->DIRECTION_OUT |= (1<<PIN_1_4_GPIO_S);
// pull up/down
uint8_t pupd_1_3 = ((PAD_CONFIG ->PORT_1_PUPD) & (0b11<<(2*PIN_1_3_GPIO_S))) >> (2*PIN_1_3_GPIO_S);
PAD_CONFIG ->PORT_1_PUPD &= (~(0b11<<(2*PIN_1_4_GPIO_S))); // clear
PAD_CONFIG ->PORT_1_PUPD |= ((pupd_1_3&0b11)<<(2*PIN_1_4_GPIO_S)); // set new
//current state
uint8_t state1_3 = ((GPIO_1->OUTPUT_) & (1<<PIN_1_3_GPIO_S)) >> PIN_1_3_GPIO_S;
GPIO_1->OUTPUT_ &= (~(0b1<<PIN_1_4_GPIO_S)); // clear
GPIO_1->OUTPUT_ |= ((state1_3&0b1)<<PIN_1_4_GPIO_S); // set new
}
else if(config == 2) // timer for pwm
{
// if D10 (spi NSS pin) was used as pwm, we need to stop timer,
// because 1.4 don't support timer
analogWriteStop(10);
ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running");
}
// switch seller to pin 1.4
HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_6, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_HIGH);
blockSpiPin();
spiInUse = true;
}
void SPIClass::end()
{
if (spiInUse && isInited)
{
// turn off spi
HAL_SPI_Disable(&hspi);
// deinit spi gpio pins
if (hspi.Instance == SPI_1) // only spi1 is using in currunt version
{
HAL_GPIO_PinConfig(GPIO_1, (HAL_PinsTypeDef)(GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2),
HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
}
// return D10 with common gpio config to pin 1.3
PAD_CONFIG->PORT_1_CFG &= (~(0b11<<(2*PIN_1_3_GPIO_S))); // set config to 0 - common gpio mode
// pin direction
uint8_t direction = ((GPIO_1->DIRECTION_IN) & (1<<PIN_1_4_GPIO_S)) >> PIN_1_4_GPIO_S;
if (direction == 1) // input
GPIO_1->DIRECTION_IN |= (1<<PIN_1_3_GPIO_S);
else // output
GPIO_1->DIRECTION_OUT |= (1<<PIN_1_3_GPIO_S);
// pull up/down
uint8_t pupd_1_4 = ((PAD_CONFIG ->PORT_1_PUPD) & (0b11<<(2*PIN_1_4_GPIO_S))) >> (2*PIN_1_4_GPIO_S);
PAD_CONFIG ->PORT_1_PUPD &= (~(0b11<<(2*PIN_1_3_GPIO_S))); // clear
PAD_CONFIG ->PORT_1_PUPD |= ((pupd_1_4&0b11)<<(2*PIN_1_3_GPIO_S)); // set new
// current state
uint8_t state1_4 = ((GPIO_1->OUTPUT_) & (1<<PIN_1_4_GPIO_S)) >> PIN_1_4_GPIO_S;
GPIO_1->OUTPUT_ &= (~(0b1<<PIN_1_3_GPIO_S)); // clear
GPIO_1->OUTPUT_ |= ((state1_4&0b1)<<PIN_1_3_GPIO_S); // set new
// switch seller back to pin 1.3
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_LOW);
unblockSpiPin();
spiInUse = false;
isInited = false;
interruptMode = 0;
interruptMask = 0;
}
}
void SPIClass::usingInterrupt(uint8_t interruptNumber)
{
if(interruptNumber < EXTERNAL_NUM_INTERRUPTS)
{
noInterrupts(); // prevent transactionBegin
interruptMask |= (1 << interruptNumber); // add new interrupt to mask
if (!interruptMode)
interruptMode = 1;
interrupts();
}
}
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
{
if(interruptNumber < EXTERNAL_NUM_INTERRUPTS)
{
noInterrupts(); // prevent transactionBegin
interruptMask &= ~(1<<interruptNumber); // delete interrupt from mask
if (!interruptMask)
interruptMode = 0;
interrupts();
}
}
void SPIClass::beginTransaction(SPISettings settings)
{
// disable interrupts in use if necessary
if (spiInUse && (interruptMode > 0))
{
for (uint8_t i = 0; i < EXTERNAL_NUM_INTERRUPTS; i++)
{
if (interruptMask & (1 << i))
// disable every interrupt by it's number
disableInterrupt(i);
}
}
// initialize spi bus or update config
if(spiInUse && ((!isInited) || newConfig))
{
// initialize spi with given settings
if (HAL_SPI_Init(&hspi) != HAL_OK)
ErrorMsgHandler("SPI.beginTransaction(): initialization error");
else
isInited = true;
}
}
uint8_t SPIClass::transfer(uint8_t data)
{
uint8_t rxByte = 0;
if (isInited)
{
// reverse bits if LSB mode needed
if (currentDataOrder == LSBFIRST)
data = reverse_bits(data);
// send and recieve data
HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&hspi, &data, &rxByte, 1, SPI_TIMEOUT_DEFAULT*2);
if (SPI_Status != HAL_OK)
HAL_SPI_ClearError(&hspi);
// reverse bits again if LSB mode needed
if (currentDataOrder == LSBFIRST)
rxByte = reverse_bits(rxByte);
}
return rxByte;
}
uint16_t SPIClass::transfer16(uint16_t data)
{
uint8_t buf[2];
uint16_t rxVal = 0;
if (isInited)
{
// prepare data for send
if (currentDataOrder == LSBFIRST)
{
// least significant byte is forward and reverse bits inside each byte
buf[0] = reverse_bits(data&0xFF);
buf[1] = reverse_bits((data>>8)&0xFF);
}
else
{
// most significant byte is forward
buf[0] = (data>>8)&0xFF;
buf[1] = data&0xFF;
}
// send and recieve data
HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&hspi, buf, buf, 2, SPI_TIMEOUT_DEFAULT*2);
if (SPI_Status != HAL_OK)
HAL_SPI_ClearError(&hspi);
// process the received data
if (currentDataOrder == LSBFIRST)
// reverse bits for LSB mode
rxVal = ( ((uint16_t)reverse_bits(buf[1]) ) << 8) | reverse_bits(buf[0]);
else
rxVal = ( ((uint16_t)buf[0]) << 8) | buf[1];
}
return rxVal;
}
void SPIClass::transfer(void *buf, size_t count)
{
if (count == 0)
return;
if (isInited)
{
uint8_t *p = (uint8_t *)buf;
// reverse bits in buffer if LSB mode needed
if (currentDataOrder == LSBFIRST)
{
for (uint32_t i = 0; i < count; i++)
*(p+i) = reverse_bits(*(p+i));
}
// send and recieve data using the same buffer
HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&hspi, (uint8_t*)buf, (uint8_t*)buf, count, SPI_TIMEOUT_DEFAULT*2);
if (SPI_Status != HAL_OK)
HAL_SPI_ClearError(&hspi);
// reverse bits if LSB mode needed
if (currentDataOrder == LSBFIRST)
{
p = (uint8_t *)buf; // return to buf beginning
for (uint32_t i = 0; i < count; i++)
*(p+i) = reverse_bits(*(p+i));
}
}
}
void SPIClass::endTransaction(void)
{
// enable interrupts in use
if (spiInUse && (interruptMode > 0))
{
for (uint8_t i = 0; i < EXTERNAL_NUM_INTERRUPTS; i++)
{
if (interruptMask & (1 << i))
// enable every interrupt in use by it's number
enableInterrupt(i);
}
}
}
// ------------------------------------ //
void SPIClass::setBitOrder(uint8_t bitOrder)
{
currentDataOrder = bitOrder;
}
void SPIClass::setDataMode(uint8_t dataMode)
{
uint32_t config = hspi.Instance->CONFIG;
HAL_SPI_Disable(&hspi);
hspi.Init.CLKPhase = dataMode & 0b00000001;
hspi.Init.CLKPolarity = (dataMode & 0b00000010)>>1;
config &= ~((1 << SPI_CONFIG_CLK_PH_S) | (1 << SPI_CONFIG_CLK_POL_S)); // clear
config |= ((hspi.Init.CLKPhase << SPI_CONFIG_CLK_PH_S) |
(hspi.Init.CLKPolarity << SPI_CONFIG_CLK_POL_S)); // set new
hspi.Instance->CONFIG = config;
HAL_SPI_Enable(&hspi);
}
void SPIClass::setClockDivider(uint8_t clockDiv)
{
// if divider is in valid range
if ((clockDiv >= SPI_CLOCK_DIV4) && (clockDiv <= SPI_CLOCK_DIV256))
{
uint32_t config = hspi.Instance->CONFIG;
HAL_SPI_Disable(&hspi);
hspi.Init.BaudRateDiv = clockDiv;
config &= ~(0b111 << SPI_CONFIG_BAUD_RATE_DIV_S); // clear
config |= (hspi.Init.BaudRateDiv << SPI_CONFIG_BAUD_RATE_DIV_S); // set new
hspi.Instance->CONFIG = config;
HAL_SPI_Enable(&hspi);
}
}
static uint8_t reverse_bits(uint8_t byte)
{
byte = (byte & 0xF0) >> 4 | (byte & 0x0F) << 4;
byte = (byte & 0xCC) >> 2 | (byte & 0x33) << 2;
byte = (byte & 0xAA) >> 1 | (byte & 0x55) << 1;
return byte;
}
+133
View File
@@ -0,0 +1,133 @@
/*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
* SPI Master library for arduino.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/
#ifndef _SPI_H_INCLUDED
#define _SPI_H_INCLUDED
#include <Arduino.h>
// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
#define SPI_HAS_TRANSACTION 1
// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method
#define SPI_HAS_NOTUSINGINTERRUPT 1
// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version.
// This way when there is a bug fix you can check this define to alert users
// of your code if it uses better version of this library.
// This also implies everything that SPI_HAS_TRANSACTION as documented above is
// available too.
#define SPI_ATOMIC_VERSION 1
#define SPI_DEFAULT_SPEED 4000000
#ifndef LSBFIRST
#define LSBFIRST 0
#endif
#ifndef MSBFIRST
#define MSBFIRST 1
#endif
// dividers for setClockDivider()
#define SPI_CLOCK_DIV4 0x01 // 8 MHz
#define SPI_CLOCK_DIV8 0x02 // 4 MHz
#define SPI_CLOCK_DIV16 0x03 // 2 MHz
#define SPI_CLOCK_DIV32 0x04 // 1 MHz
#define SPI_CLOCK_DIV64 0x05 // 500 kHz
#define SPI_CLOCK_DIV128 0x06 // 250 kHz
#define SPI_CLOCK_DIV256 0x07 // 125 kHz
// mode[1] - polarity, mode[0] - phase
#define SPI_MODE0 0b00
#define SPI_MODE1 0b01
#define SPI_MODE2 0b10
#define SPI_MODE3 0b11
class SPISettings
{
public:
SPISettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode)
{
spiUpdateSettings(speedMaximum, dataOrder, dataMode);
}
SPISettings()
{
spiUpdateSettings(SPI_DEFAULT_SPEED, MSBFIRST, SPI_MODE0);
}
private:
void spiUpdateSettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode);
friend class SPIClass;
};
class SPIClass
{
private:
static bool spiInUse;
static uint8_t interruptMode; // 0=none, 1=mask
static uint8_t interruptMask; // which interrupts to mask
public:
// Initialize the SPI library
static void begin();
// If SPI is used from within an interrupt, this function registers
// that interrupt with the SPI library, so beginTransaction() can
// prevent conflicts. The input interruptNumber is the number used
// with attachInterrupt.
static void usingInterrupt(uint8_t interruptNumber);
// And this does the opposite.
static void notUsingInterrupt(uint8_t interruptNumber);
// Note: the usingInterrupt and notUsingInterrupt functions should
// not to be called from ISR context or inside a transaction.
// For details see:
// https://github.com/arduino/Arduino/pull/2381
// https://github.com/arduino/Arduino/pull/2449
// Before using SPI.transfer() or asserting chip select pins,
// this function is used to gain exclusive access to the SPI bus
// and configure the correct settings.
void beginTransaction(SPISettings settings);
// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
uint8_t transfer(uint8_t data);
uint16_t transfer16(uint16_t data);
void transfer(void *buf, size_t count);
// After performing a group of transfers and releasing the chip select
// signal, this function allows others to access the SPI bus
void endTransaction(void);
// Disable the SPI bus
static void end();
// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
void setBitOrder(uint8_t bitOrder);
// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
void setDataMode(uint8_t dataMode);
// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
void setClockDivider(uint8_t clockDiv);
};
extern SPIClass SPI;
#endif
+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__ */