Fixes for Arduino_Core_STM32 V2.0 (#592)
Fixes and added FRAM to the code Fixes for Teensy 4.1
This commit is contained in:
parent
1da3fb1304
commit
9022bffb0a
|
@ -26,7 +26,9 @@
|
||||||
#define micros_safe() micros() //timer5 method is not used on anything but AVR, the micros_safe() macro is simply an alias for the normal micros()
|
#define micros_safe() micros() //timer5 method is not used on anything but AVR, the micros_safe() macro is simply an alias for the normal micros()
|
||||||
#define TIMER_RESOLUTION 4
|
#define TIMER_RESOLUTION 4
|
||||||
|
|
||||||
|
#ifdef SD_LOGGING
|
||||||
#define RTC_ENABLED
|
#define RTC_ENABLED
|
||||||
|
#endif
|
||||||
#define USE_SERIAL3
|
#define USE_SERIAL3
|
||||||
|
|
||||||
//When building for Black board Serial1 is instanciated,building generic STM32F4x7 has serial2 and serial 1 must be done here
|
//When building for Black board Serial1 is instanciated,building generic STM32F4x7 has serial2 and serial 1 must be done here
|
||||||
|
@ -90,7 +92,7 @@ extern "C" char* sbrk(int incr);
|
||||||
extern SPI_EEPROM_Class EEPROM;
|
extern SPI_EEPROM_Class EEPROM;
|
||||||
|
|
||||||
#elif defined(FRAM_AS_EEPROM) //https://github.com/VitorBoss/FRAM
|
#elif defined(FRAM_AS_EEPROM) //https://github.com/VitorBoss/FRAM
|
||||||
#define EEPROM_LIB_H <Fram.h>
|
#define EEPROM_LIB_H "src/FRAM/Fram.h"
|
||||||
#include EEPROM_LIB_H
|
#include EEPROM_LIB_H
|
||||||
#if defined(STM32F407xx)
|
#if defined(STM32F407xx)
|
||||||
extern FramClass EEPROM; /*(mosi, miso, sclk, ssel, clockspeed) 31/01/2020*/
|
extern FramClass EEPROM; /*(mosi, miso, sclk, ssel, clockspeed) 31/01/2020*/
|
||||||
|
|
|
@ -23,9 +23,11 @@ STM32_CAN Can0 (_CAN1,DEF);
|
||||||
SPI_EEPROM_Class EEPROM(EmulatedEEPROMMconfig, SPIconfig);
|
SPI_EEPROM_Class EEPROM(EmulatedEEPROMMconfig, SPIconfig);
|
||||||
#elif defined(FRAM_AS_EEPROM) //https://github.com/VitorBoss/FRAM
|
#elif defined(FRAM_AS_EEPROM) //https://github.com/VitorBoss/FRAM
|
||||||
#if defined(STM32F407xx)
|
#if defined(STM32F407xx)
|
||||||
FramClass EEPROM(PB5, PB4, PB3, PB0); /*(mosi, miso, sclk, ssel, clockspeed) 31/01/2020*/
|
SPIClass SPI_for_FRAM(PB5, PB4, PB3); //SPI1_MOSI, SPI1_MISO, SPI1_SCK
|
||||||
#else
|
FramClass EEPROM(PB0, SPI_for_FRAM);
|
||||||
FramClass EEPROM(PB15, PB14, PB13, PB12); //Blue/Black Pills
|
#else //Blue/Black Pills
|
||||||
|
SPIClass SPI_for_FRAM(PB15, PB14, PB13);
|
||||||
|
FramClass EEPROM(PB12, SPI_for_FRAM);
|
||||||
#endif
|
#endif
|
||||||
#elif defined(STM32F7xx)
|
#elif defined(STM32F7xx)
|
||||||
#if defined(DUAL_BANK)
|
#if defined(DUAL_BANK)
|
||||||
|
@ -56,7 +58,9 @@ HardwareTimer Timer11(TIM7);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef RTC_ENABLED
|
||||||
STM32RTC& rtc = STM32RTC::getInstance();
|
STM32RTC& rtc = STM32RTC::getInstance();
|
||||||
|
#endif
|
||||||
|
|
||||||
void initBoard()
|
void initBoard()
|
||||||
{
|
{
|
||||||
|
@ -70,13 +74,13 @@ STM32RTC& rtc = STM32RTC::getInstance();
|
||||||
delay(10);
|
delay(10);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
***********************************************************************************************************
|
***********************************************************************************************************
|
||||||
* Real Time clock for datalogging/time stamping
|
* Real Time clock for datalogging/time stamping
|
||||||
*/
|
*/
|
||||||
|
#ifdef RTC_ENABLED
|
||||||
rtc.setClockSource(STM32RTC::LSE_CLOCK); //Initialize external clock for RTC. That is the only clock running of VBAT
|
rtc.setClockSource(STM32RTC::LSE_CLOCK); //Initialize external clock for RTC. That is the only clock running of VBAT
|
||||||
rtc.begin(); // initialize RTC 24H format
|
rtc.begin(); // initialize RTC 24H format
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
***********************************************************************************************************
|
***********************************************************************************************************
|
||||||
* Idle
|
* Idle
|
||||||
|
@ -87,7 +91,11 @@ STM32RTC& rtc = STM32RTC::getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
//This must happen at the end of the idle init
|
//This must happen at the end of the idle init
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer1.setMode(4, TIMER_OUTPUT_COMPARE);
|
Timer1.setMode(4, TIMER_OUTPUT_COMPARE);
|
||||||
|
#else
|
||||||
|
Timer1.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
#endif
|
||||||
Timer1.attachInterrupt(4, idleInterrupt); //on first flash the configPage4.iacAlgorithm is invalid
|
Timer1.attachInterrupt(4, idleInterrupt); //on first flash the configPage4.iacAlgorithm is invalid
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,13 +105,21 @@ STM32RTC& rtc = STM32RTC::getInstance();
|
||||||
*/
|
*/
|
||||||
#if defined(ARDUINO_BLUEPILL_F103C8) || defined(ARDUINO_BLUEPILL_F103CB)
|
#if defined(ARDUINO_BLUEPILL_F103C8) || defined(ARDUINO_BLUEPILL_F103CB)
|
||||||
Timer4.setOverflow(1000, MICROSEC_FORMAT); // Set up period
|
Timer4.setOverflow(1000, MICROSEC_FORMAT); // Set up period
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
|
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
|
||||||
Timer4.attachInterrupt(1, oneMSInterval);
|
Timer4.attachInterrupt(1, oneMSInterval);
|
||||||
|
#else //2.0 forward
|
||||||
|
Timer4.attachInterrupt(oneMSInterval);
|
||||||
|
#endif
|
||||||
Timer4.resume(); //Start Timer
|
Timer4.resume(); //Start Timer
|
||||||
#else
|
#else
|
||||||
Timer11.setOverflow(1000, MICROSEC_FORMAT); // Set up period
|
Timer11.setOverflow(1000, MICROSEC_FORMAT); // Set up period
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer11.setMode(1, TIMER_OUTPUT_COMPARE);
|
Timer11.setMode(1, TIMER_OUTPUT_COMPARE);
|
||||||
Timer11.attachInterrupt(1, oneMSInterval);
|
Timer11.attachInterrupt(1, oneMSInterval);
|
||||||
|
#else
|
||||||
|
Timer11.attachInterrupt(oneMSInterval);
|
||||||
|
#endif
|
||||||
Timer11.resume(); //Start Timer
|
Timer11.resume(); //Start Timer
|
||||||
#endif
|
#endif
|
||||||
pinMode(LED_BUILTIN, OUTPUT); //Visual WDT
|
pinMode(LED_BUILTIN, OUTPUT); //Visual WDT
|
||||||
|
@ -117,8 +133,13 @@ STM32RTC& rtc = STM32RTC::getInstance();
|
||||||
vvt_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle
|
vvt_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle
|
||||||
|
|
||||||
//Need to be initialised last due to instant interrupt
|
//Need to be initialised last due to instant interrupt
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer1.setMode(2, TIMER_OUTPUT_COMPARE);
|
Timer1.setMode(2, TIMER_OUTPUT_COMPARE);
|
||||||
Timer1.setMode(3, TIMER_OUTPUT_COMPARE);
|
Timer1.setMode(3, TIMER_OUTPUT_COMPARE);
|
||||||
|
#else //2.0 forward
|
||||||
|
Timer1.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
Timer1.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
#endif
|
||||||
Timer1.attachInterrupt(2, boostInterrupt);
|
Timer1.attachInterrupt(2, boostInterrupt);
|
||||||
Timer1.attachInterrupt(3, vvtInterrupt);
|
Timer1.attachInterrupt(3, vvtInterrupt);
|
||||||
|
|
||||||
|
@ -134,6 +155,7 @@ STM32RTC& rtc = STM32RTC::getInstance();
|
||||||
Timer2.setPrescaleFactor(((Timer2.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
|
Timer2.setPrescaleFactor(((Timer2.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
|
||||||
Timer3.setPrescaleFactor(((Timer3.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
|
Timer3.setPrescaleFactor(((Timer3.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
|
||||||
|
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer2.setMode(1, TIMER_OUTPUT_COMPARE);
|
Timer2.setMode(1, TIMER_OUTPUT_COMPARE);
|
||||||
Timer2.setMode(2, TIMER_OUTPUT_COMPARE);
|
Timer2.setMode(2, TIMER_OUTPUT_COMPARE);
|
||||||
Timer2.setMode(3, TIMER_OUTPUT_COMPARE);
|
Timer2.setMode(3, TIMER_OUTPUT_COMPARE);
|
||||||
|
@ -144,7 +166,18 @@ STM32RTC& rtc = STM32RTC::getInstance();
|
||||||
Timer3.setMode(3, TIMER_OUTPUT_COMPARE);
|
Timer3.setMode(3, TIMER_OUTPUT_COMPARE);
|
||||||
Timer3.setMode(4, TIMER_OUTPUT_COMPARE);
|
Timer3.setMode(4, TIMER_OUTPUT_COMPARE);
|
||||||
Timer1.setMode(1, TIMER_OUTPUT_COMPARE);
|
Timer1.setMode(1, TIMER_OUTPUT_COMPARE);
|
||||||
|
#else //2.0 forward
|
||||||
|
Timer2.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
Timer2.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
Timer2.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
Timer2.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
|
||||||
|
Timer3.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
Timer3.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
Timer3.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
Timer3.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
Timer1.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
#endif
|
||||||
//Attach interrupt functions
|
//Attach interrupt functions
|
||||||
//Injection
|
//Injection
|
||||||
Timer3.attachInterrupt(1, fuelSchedule1Interrupt);
|
Timer3.attachInterrupt(1, fuelSchedule1Interrupt);
|
||||||
|
@ -154,19 +187,35 @@ STM32RTC& rtc = STM32RTC::getInstance();
|
||||||
#if (INJ_CHANNELS >= 5)
|
#if (INJ_CHANNELS >= 5)
|
||||||
Timer5.setOverflow(0xFFFF, TICK_FORMAT);
|
Timer5.setOverflow(0xFFFF, TICK_FORMAT);
|
||||||
Timer5.setPrescaleFactor(((Timer5.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
|
Timer5.setPrescaleFactor(((Timer5.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer5.setMode(1, TIMER_OUTPUT_COMPARE);
|
Timer5.setMode(1, TIMER_OUTPUT_COMPARE);
|
||||||
|
#else //2.0 forward
|
||||||
|
Timer5.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
#endif
|
||||||
Timer5.attachInterrupt(1, fuelSchedule5Interrupt);
|
Timer5.attachInterrupt(1, fuelSchedule5Interrupt);
|
||||||
#endif
|
#endif
|
||||||
#if (INJ_CHANNELS >= 6)
|
#if (INJ_CHANNELS >= 6)
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer5.setMode(2, TIMER_OUTPUT_COMPARE);
|
Timer5.setMode(2, TIMER_OUTPUT_COMPARE);
|
||||||
|
#else //2.0 forward
|
||||||
|
Timer5.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
#endif
|
||||||
Timer5.attachInterrupt(2, fuelSchedule6Interrupt);
|
Timer5.attachInterrupt(2, fuelSchedule6Interrupt);
|
||||||
#endif
|
#endif
|
||||||
#if (INJ_CHANNELS >= 7)
|
#if (INJ_CHANNELS >= 7)
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer5.setMode(3, TIMER_OUTPUT_COMPARE);
|
Timer5.setMode(3, TIMER_OUTPUT_COMPARE);
|
||||||
|
#else //2.0 forward
|
||||||
|
Timer5.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
#endif
|
||||||
Timer5.attachInterrupt(3, fuelSchedule7Interrupt);
|
Timer5.attachInterrupt(3, fuelSchedule7Interrupt);
|
||||||
#endif
|
#endif
|
||||||
#if (INJ_CHANNELS >= 8)
|
#if (INJ_CHANNELS >= 8)
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer5.setMode(4, TIMER_OUTPUT_COMPARE);
|
Timer5.setMode(4, TIMER_OUTPUT_COMPARE);
|
||||||
|
#else //2.0 forward
|
||||||
|
Timer5.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
#endif
|
||||||
Timer5.attachInterrupt(4, fuelSchedule8Interrupt);
|
Timer5.attachInterrupt(4, fuelSchedule8Interrupt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -178,19 +227,35 @@ STM32RTC& rtc = STM32RTC::getInstance();
|
||||||
#if (IGN_CHANNELS >= 5)
|
#if (IGN_CHANNELS >= 5)
|
||||||
Timer4.setOverflow(0xFFFF, TICK_FORMAT);
|
Timer4.setOverflow(0xFFFF, TICK_FORMAT);
|
||||||
Timer4.setPrescaleFactor(((Timer4.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
|
Timer4.setPrescaleFactor(((Timer4.getTimerClkFreq()/1000000) * TIMER_RESOLUTION)-1); //4us resolution
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
|
Timer4.setMode(1, TIMER_OUTPUT_COMPARE);
|
||||||
|
#else //2.0 forward
|
||||||
|
Timer4.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
#endif
|
||||||
Timer4.attachInterrupt(1, ignitionSchedule5Interrupt);
|
Timer4.attachInterrupt(1, ignitionSchedule5Interrupt);
|
||||||
#endif
|
#endif
|
||||||
#if (IGN_CHANNELS >= 6)
|
#if (IGN_CHANNELS >= 6)
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer4.setMode(2, TIMER_OUTPUT_COMPARE);
|
Timer4.setMode(2, TIMER_OUTPUT_COMPARE);
|
||||||
|
#else //2.0 forward
|
||||||
|
Timer4.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
#endif
|
||||||
Timer4.attachInterrupt(2, ignitionSchedule6Interrupt);
|
Timer4.attachInterrupt(2, ignitionSchedule6Interrupt);
|
||||||
#endif
|
#endif
|
||||||
#if (IGN_CHANNELS >= 7)
|
#if (IGN_CHANNELS >= 7)
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer4.setMode(3, TIMER_OUTPUT_COMPARE);
|
Timer4.setMode(3, TIMER_OUTPUT_COMPARE);
|
||||||
|
#else //2.0 forward
|
||||||
|
Timer4.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
#endif
|
||||||
Timer4.attachInterrupt(3, ignitionSchedule7Interrupt);
|
Timer4.attachInterrupt(3, ignitionSchedule7Interrupt);
|
||||||
#endif
|
#endif
|
||||||
#if (IGN_CHANNELS >= 8)
|
#if (IGN_CHANNELS >= 8)
|
||||||
|
#if ( STM32_CORE_VERSION_MAJOR < 2 )
|
||||||
Timer4.setMode(4, TIMER_OUTPUT_COMPARE);
|
Timer4.setMode(4, TIMER_OUTPUT_COMPARE);
|
||||||
|
#else //2.0 forward
|
||||||
|
Timer4.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
|
||||||
|
#endif
|
||||||
Timer4.attachInterrupt(4, ignitionSchedule8Interrupt);
|
Timer4.attachInterrupt(4, ignitionSchedule8Interrupt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,360 @@
|
||||||
|
// Basic read/write functions for the MB85RS64A SPI FRAM chip
|
||||||
|
// Copyright (C) 2017 Industruino <connect@industruino.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
//
|
||||||
|
// Developed by Claudio Indellicati <bitron.it@gmail.com>
|
||||||
|
//
|
||||||
|
// Mod by Vitor_Boss on 01/2019
|
||||||
|
// work with STM32
|
||||||
|
// added option to use any SPI port
|
||||||
|
// added software version of SPI with configurable speed
|
||||||
|
|
||||||
|
#include "Fram.h"
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
SPISettings FRAMSettings(FRAM_DEFAULT_CLOCK, MSBFIRST, SPI_MODE0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void FramClass::assertCS(void)
|
||||||
|
{
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
spi->beginTransaction(FRAMSettings);
|
||||||
|
#endif
|
||||||
|
*csPort &= ~(csMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FramClass::deassertCS(void)
|
||||||
|
{
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
spi->endTransaction();
|
||||||
|
#endif
|
||||||
|
*csPort |= (csMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
FramClass::FramClass(void)
|
||||||
|
{
|
||||||
|
clkPin = mosiPin = misoPin = NC;
|
||||||
|
csPin = FRAM_DEFAULT_CS_PIN;
|
||||||
|
csPinInit();
|
||||||
|
begin(csPin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_STM32) || defined(__IMXRT1062__)
|
||||||
|
FramClass::FramClass (uint32_t ssel, SPIClass &_spi)
|
||||||
|
#else
|
||||||
|
FramClass::FramClass (uint8_t ssel, SPIClass &_spi)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
clkPin = mosiPin = misoPin = NC;
|
||||||
|
begin(ssel, _spi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_STM32) || defined(__IMXRT1062__)
|
||||||
|
FramClass::FramClass (uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel, uint32_t clockspeed)
|
||||||
|
#else
|
||||||
|
FramClass::FramClass (uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel, uint32_t clockspeed)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
csPin = ssel;
|
||||||
|
clkPin = sclk;
|
||||||
|
misoPin = miso;
|
||||||
|
mosiPin = mosi;
|
||||||
|
setClock(clockspeed);
|
||||||
|
csPinInit();
|
||||||
|
|
||||||
|
if (clkPin != NC)
|
||||||
|
{
|
||||||
|
pinMode(clkPin, OUTPUT);
|
||||||
|
clkPort = portOutputRegister(digitalPinToPort(clkPin));
|
||||||
|
clkMask = digitalPinToBitMask(clkPin);
|
||||||
|
}
|
||||||
|
if (mosiPin != NC)
|
||||||
|
{
|
||||||
|
pinMode(mosiPin, OUTPUT);
|
||||||
|
mosiPort = portOutputRegister(digitalPinToPort(mosiPin));
|
||||||
|
mosiMask = digitalPinToBitMask(mosiPin);
|
||||||
|
}
|
||||||
|
// Set CS pin HIGH and configure it as an output
|
||||||
|
pinMode(csPin, OUTPUT);
|
||||||
|
pinMode(misoPin, INPUT_PULLUP);
|
||||||
|
deassertCS();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void FramClass::enableWrite (uint8_t state)
|
||||||
|
{
|
||||||
|
assertCS();
|
||||||
|
if (state){ spiSend(FRAM_CMD_WREN); }
|
||||||
|
else { spiSend(FRAM_CMD_WRDI); }
|
||||||
|
deassertCS();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void FramClass::setClock(uint32_t clockSpeed) {
|
||||||
|
spiSpeed = 1000000 / (clockSpeed * 2);
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
FRAMSettings = SPISettings(clockSpeed, MSBFIRST, SPI_MODE0);
|
||||||
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
|
spi->beginTransaction(csPin, FRAMSettings);
|
||||||
|
#else
|
||||||
|
spi->beginTransaction(FRAMSettings);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint8_t FramClass::isDeviceActive(void) {
|
||||||
|
uint8_t result;
|
||||||
|
enableWrite(1); //Best way of detecting a device
|
||||||
|
char SR = readSR();
|
||||||
|
result = (SR!=0) && (SR!=255);
|
||||||
|
enableWrite(0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_STM32) || defined(__IMXRT1062__)
|
||||||
|
void FramClass::begin (uint32_t ssel, SPIClass &_spi)
|
||||||
|
#else
|
||||||
|
void FramClass::begin (uint8_t ssel, SPIClass &_spi)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
clkPin = mosiPin = misoPin = NC;
|
||||||
|
csPin = ssel;
|
||||||
|
spi = &_spi;
|
||||||
|
|
||||||
|
// Set CS pin HIGH and configure it as an output
|
||||||
|
csPinInit();
|
||||||
|
deassertCS();
|
||||||
|
setClock(FRAM_DEFAULT_CLOCK);
|
||||||
|
#ifdef SPI_HAS_TRANSACTION
|
||||||
|
spi->begin();
|
||||||
|
spi->beginTransaction(FRAMSettings);
|
||||||
|
#else
|
||||||
|
#if defined(STM32F2)
|
||||||
|
spi->setClockDivider (SPI_CLOCK_DIV4); // SPI @ 15MHz
|
||||||
|
#elif defined(STM32F4)
|
||||||
|
spi->setClockDivider (SPI_CLOCK_DIV16);
|
||||||
|
#else
|
||||||
|
spi->setClockDivider (SPI_CLOCK_DIV2); // 8 MHz
|
||||||
|
#endif
|
||||||
|
spi->setDataMode(SPI_MODE0);
|
||||||
|
spi->begin();
|
||||||
|
#endif
|
||||||
|
delayMicroseconds(15);//>3us
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint8_t FramClass::write (uint32_t addr, uint8_t data)
|
||||||
|
{
|
||||||
|
enableWrite(1);
|
||||||
|
assertCS();
|
||||||
|
spiSend(FRAM_CMD_WRITE);
|
||||||
|
sendAddr(addr);
|
||||||
|
spiSend(data);
|
||||||
|
deassertCS();
|
||||||
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
|
delayMicroseconds(5);
|
||||||
|
#else
|
||||||
|
SOFT_DELAY(5);
|
||||||
|
#endif
|
||||||
|
enableWrite(0);
|
||||||
|
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint8_t FramClass::write (uint32_t addr, uint8_t *data, uint16_t count)
|
||||||
|
{
|
||||||
|
if (addr + count > FRAM_SIZE)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
if (count == 0U)
|
||||||
|
return 255;
|
||||||
|
|
||||||
|
enableWrite(1);
|
||||||
|
assertCS();
|
||||||
|
spiSend(FRAM_CMD_WRITE);
|
||||||
|
sendAddr(addr);
|
||||||
|
for (uint16_t i = 0; i < count; ++i)
|
||||||
|
spiSend(data[i]);
|
||||||
|
deassertCS();
|
||||||
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
|
delayMicroseconds(5);
|
||||||
|
#else
|
||||||
|
SOFT_DELAY(5);
|
||||||
|
#endif
|
||||||
|
enableWrite(0);
|
||||||
|
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint8_t FramClass::read (uint32_t addr, uint8_t *dataBuffer, uint16_t count)
|
||||||
|
{
|
||||||
|
if (addr + count > FRAM_SIZE)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
if (count == 0U)
|
||||||
|
return 255;
|
||||||
|
|
||||||
|
assertCS();
|
||||||
|
spiSend(FRAM_CMD_READ);
|
||||||
|
sendAddr(addr);
|
||||||
|
for (uint16_t i=0; i < count; ++i)
|
||||||
|
dataBuffer[i] = spiSend(DUMMYBYTE);
|
||||||
|
deassertCS();
|
||||||
|
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint8_t FramClass::read (uint32_t addr)
|
||||||
|
{
|
||||||
|
uint8_t dataBuffer;
|
||||||
|
|
||||||
|
assertCS();
|
||||||
|
spiSend(FRAM_CMD_READ);
|
||||||
|
sendAddr(addr);
|
||||||
|
dataBuffer = spiSend(DUMMYBYTE);
|
||||||
|
deassertCS();
|
||||||
|
|
||||||
|
return dataBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint8_t FramClass::update (uint32_t addr, uint8_t data)
|
||||||
|
{
|
||||||
|
if(read(addr) != data)
|
||||||
|
write(addr, data);
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t FramClass::clear(void)
|
||||||
|
{
|
||||||
|
enableWrite(1);
|
||||||
|
assertCS();
|
||||||
|
spiSend(FRAM_CMD_WRITE);
|
||||||
|
sendAddr(0x0000);
|
||||||
|
for (uint32_t i = 0; i < FRAM_SIZE; ++i)
|
||||||
|
spiSend(0x00);
|
||||||
|
deassertCS();
|
||||||
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
|
delayMicroseconds(5);
|
||||||
|
#else
|
||||||
|
SOFT_DELAY(5);
|
||||||
|
#endif
|
||||||
|
enableWrite(0);
|
||||||
|
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint8_t FramClass::readSR(void)
|
||||||
|
{
|
||||||
|
uint8_t dataBuffer;
|
||||||
|
|
||||||
|
assertCS();
|
||||||
|
spiSend(FRAM_CMD_RDSR);
|
||||||
|
dataBuffer = spiSend(DUMMYBYTE);
|
||||||
|
deassertCS();
|
||||||
|
|
||||||
|
return dataBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
void FramClass::sendAddr(uint32_t addr)
|
||||||
|
{
|
||||||
|
spiSend16(addr & 0xFFFF);
|
||||||
|
#if((FRAM_SIZE > 0xFFFF) && (FRAM_SIZE <= 0x00FFFFFF))
|
||||||
|
spiSend((addr>>16) & 0xFF);
|
||||||
|
#elif(FRAM_SIZE >= 0x00FFFFFF)
|
||||||
|
spiSend16((addr>>16) & 0xFFFF);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t FramClass::length(void)
|
||||||
|
{
|
||||||
|
return FRAM_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t FramClass::spiSend(uint8_t data)
|
||||||
|
{
|
||||||
|
uint8_t reply = 0;
|
||||||
|
if(clkPin != NC)
|
||||||
|
{
|
||||||
|
for (int i=7; i>=0; i--)
|
||||||
|
{
|
||||||
|
reply <<= 1;
|
||||||
|
setClockPin(LOW);
|
||||||
|
fastWrite(mosiPort, mosiMask, (data & ((uint8_t)1<<i)));
|
||||||
|
setClockPin(HIGH);
|
||||||
|
reply |= digitalRead(misoPin);
|
||||||
|
}
|
||||||
|
fastWrite(clkPort, clkMask, LOW);
|
||||||
|
}
|
||||||
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
|
else { reply = spi->transfer(csPin, data, SPI_CONTINUE); }
|
||||||
|
#else
|
||||||
|
else { reply = spi->transfer(data); }
|
||||||
|
#endif
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint16_t FramClass::spiSend16(uint16_t data)
|
||||||
|
{
|
||||||
|
uint16_t reply = 0;
|
||||||
|
if(clkPin != NC)
|
||||||
|
{
|
||||||
|
for (int i=15; i>=0; i--)
|
||||||
|
{
|
||||||
|
reply <<= 1;
|
||||||
|
setClockPin(LOW);
|
||||||
|
fastWrite(mosiPort, mosiMask, (data & ((uint16_t)1<<i)));
|
||||||
|
setClockPin(HIGH);
|
||||||
|
reply |= digitalRead(misoPin);
|
||||||
|
}
|
||||||
|
fastWrite(clkPort, clkMask, LOW);
|
||||||
|
}
|
||||||
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
|
else { reply = spi->transfer16(csPin, data, SPI_CONTINUE); }
|
||||||
|
#else
|
||||||
|
else { reply = spi->transfer16(data); }
|
||||||
|
#endif
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
//FramClass Fram;
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
// Basic read/write functions for the MB85RS64A SPI FRAM chip
|
||||||
|
// Copyright (C) 2017 Industruino <connect@industruino.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
//
|
||||||
|
// Developed by Claudio Indellicati <bitron.it@gmail.com>
|
||||||
|
// Added features by Vitor_Boss <vitor_boss@yahoo.com.br>
|
||||||
|
|
||||||
|
#ifndef __FRAM_H__
|
||||||
|
#define __FRAM_H__
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
#define FRAM_DEFAULT_CS_PIN ((uint8_t) 16)
|
||||||
|
|
||||||
|
#if defined (ARDUINO_ARCH_AVR)
|
||||||
|
#define FRAM_DEFAULT_CLOCK 4000000 //value in Hz
|
||||||
|
#else
|
||||||
|
#define FRAM_DEFAULT_CLOCK 16000000 //value in Hz
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NC
|
||||||
|
#define NC 255
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SOFT_DELAY(x) do{for(uint32_t i=x;i>0;i--) {asm volatile("nop");}}while(0)
|
||||||
|
|
||||||
|
// MB85RS64A - 256 K (32 K x 8) bit SPI FRAM
|
||||||
|
#define FRAM_SIZE 0x8000UL
|
||||||
|
|
||||||
|
#define DUMMYBYTE 0xFE //dummy bytes to make easier to sniff
|
||||||
|
|
||||||
|
#define FRAM_CMD_WREN 0x06 //write enable
|
||||||
|
#define FRAM_CMD_WRDI 0x04 //write disable
|
||||||
|
#define FRAM_CMD_RDSR 0x05 //read status reg
|
||||||
|
#define FRAM_CMD_WRSR 0x01 //write status reg
|
||||||
|
#define FRAM_CMD_READ 0x03
|
||||||
|
#define FRAM_CMD_WRITE 0x02
|
||||||
|
//Not for all devices
|
||||||
|
#define FRAM_CMD_FSTRD 0x0B //fast read
|
||||||
|
#define FRAM_CMD_SLEEP 0xB9 //power down
|
||||||
|
#define FRAM_CMD_RDID 0x9F //read JEDEC ID = Manuf+ID (suggested)
|
||||||
|
#define FRAM_CMD_SNR 0xC3 //Reads 8-byte serial number
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class FramClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FramClass();
|
||||||
|
#if defined(ARDUINO_ARCH_STM32) || defined(__IMXRT1062__)
|
||||||
|
FramClass(uint32_t mosi, uint32_t miso, uint32_t sclk, uint32_t ssel = FRAM_DEFAULT_CS_PIN, uint32_t clockspeed = FRAM_DEFAULT_CLOCK);
|
||||||
|
FramClass(uint32_t ssel = FRAM_DEFAULT_CS_PIN, SPIClass &_spi = SPI);
|
||||||
|
void begin (uint32_t ssel = FRAM_DEFAULT_CS_PIN, SPIClass &_spi = SPI);
|
||||||
|
#else
|
||||||
|
FramClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t ssel = FRAM_DEFAULT_CS_PIN, uint32_t clockspeed = FRAM_DEFAULT_CLOCK);
|
||||||
|
FramClass(uint8_t ssel = FRAM_DEFAULT_CS_PIN, SPIClass &_spi = SPI);
|
||||||
|
void begin (uint8_t ssel = FRAM_DEFAULT_CS_PIN, SPIClass &_spi = SPI);
|
||||||
|
#endif
|
||||||
|
void enableWrite (uint8_t state);
|
||||||
|
void setClock(uint32_t clockSpeed);
|
||||||
|
uint8_t write (uint32_t addr, uint8_t *data, uint16_t count);
|
||||||
|
uint8_t write (uint32_t addr, uint8_t data);
|
||||||
|
uint8_t read (uint32_t addr, uint8_t *dataBuffer, uint16_t count);
|
||||||
|
uint8_t read (uint32_t addr);
|
||||||
|
uint8_t update (uint32_t addr, uint8_t data);
|
||||||
|
uint8_t readSR (void);
|
||||||
|
uint8_t isDeviceActive (void);
|
||||||
|
uint8_t clear (void);
|
||||||
|
uint32_t length (void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read AnyTypeOfData from eeprom
|
||||||
|
* @param address
|
||||||
|
* @return AnyTypeOfData
|
||||||
|
*/
|
||||||
|
template< typename T > T &get( int idx, T &t ){
|
||||||
|
uint16_t e = idx;
|
||||||
|
uint8_t *ptr = (uint8_t*) &t;
|
||||||
|
for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = read(e);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write AnyTypeOfData to eeprom
|
||||||
|
* @param address
|
||||||
|
* @param AnyTypeOfData
|
||||||
|
* @return number of bytes written to flash
|
||||||
|
*/
|
||||||
|
template< typename T > const T &put( int idx, const T &t ){
|
||||||
|
const uint8_t *ptr = (const uint8_t*) &t;
|
||||||
|
uint16_t e = idx;
|
||||||
|
for( int count = sizeof(T) ; count ; --count, ++e ) write(e, *ptr++);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(ARDUINO_ARCH_STM32) || defined(__IMXRT1062__)
|
||||||
|
volatile uint32_t mosiMask, *mosiPort;
|
||||||
|
volatile uint32_t clkMask, *clkPort;
|
||||||
|
volatile uint32_t csMask, *csPort;
|
||||||
|
#else
|
||||||
|
volatile uint8_t mosiMask, *mosiPort;
|
||||||
|
volatile uint8_t clkMask, *clkPort;
|
||||||
|
volatile uint8_t csMask, *csPort;
|
||||||
|
#endif
|
||||||
|
uint8_t csPin, clkPin, mosiPin, misoPin;
|
||||||
|
uint32_t spiSpeed;
|
||||||
|
SPIClass *spi;
|
||||||
|
// #define assertCS *csPort &= ~(csMask); //fastWrite(csPort, csMask, LOW);
|
||||||
|
// #define deassertCS *csPort |= (csMask); //fastWrite(csPort, csMask, HIGH);
|
||||||
|
void assertCS(void);
|
||||||
|
void deassertCS(void);
|
||||||
|
void sendAddr(uint32_t addr);
|
||||||
|
uint8_t spiSend(uint8_t data);
|
||||||
|
uint16_t spiSend16(uint16_t data);
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_STM32) || defined(__IMXRT1062__)
|
||||||
|
inline void fastWrite(volatile uint32_t *port, uint32_t pin, int8_t state)
|
||||||
|
#else
|
||||||
|
inline void fastWrite(volatile uint8_t *port, uint8_t pin, int8_t state)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (state == LOW) *port &= ~(pin);
|
||||||
|
else *port |= (pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setClockPin(int8_t state)
|
||||||
|
{
|
||||||
|
fastWrite(clkPort, clkMask, state);
|
||||||
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
|
delayMicroseconds(spiSpeed);
|
||||||
|
#else
|
||||||
|
SOFT_DELAY(spiSpeed);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void csPinInit()
|
||||||
|
{
|
||||||
|
pinMode(csPin, OUTPUT);
|
||||||
|
csPort = portOutputRegister(digitalPinToPort(csPin));
|
||||||
|
csMask = digitalPinToBitMask(csPin);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __FRAM_H__
|
||||||
|
|
Loading…
Reference in New Issue