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:
Vitor Moreno B. Sales 2021-07-03 22:30:12 -03:00 committed by GitHub
parent 1da3fb1304
commit 9022bffb0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 600 additions and 11 deletions

View File

@ -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*/

View File

@ -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

360
speeduino/src/FRAM/Fram.cpp Normal file
View File

@ -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;

162
speeduino/src/FRAM/Fram.h Normal file
View File

@ -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__