ready to alpha
подготовка к альфа-тестированию
This commit is contained in:
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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
#######################################
|
||||
@@ -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
|
||||
@@ -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( );
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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__ */
|
||||
|
||||
Reference in new issue
Block a user