first commit
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Test2.cpp
|
||||
*
|
||||
* Created on: 22.07.2016
|
||||
* Author: danilo
|
||||
*/
|
||||
|
||||
#include "TestCPlusPlusBuild.h"
|
||||
#include "TestCPlusPlusInterface.h"
|
||||
|
||||
#ifdef TESTCPLUSPLUS
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
Test2 t2;
|
||||
|
||||
void test_call_cpp()
|
||||
{
|
||||
t2.doIt();
|
||||
}
|
||||
|
||||
void Test2::doIt()
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
|
||||
Test2::Test2(): stringTest("TestOK"), done(false)
|
||||
{
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
Test2::~Test2()
|
||||
{
|
||||
// TODO Auto-generated destructor stub
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Test2.h
|
||||
*
|
||||
* Created on: 22.07.2016
|
||||
* Author: danilo
|
||||
*/
|
||||
|
||||
#ifndef MISC_TESTCPLUSPLUSBUILD_H_
|
||||
#define MISC_TESTCPLUSPLUSBUILD_H_
|
||||
|
||||
#include "TestCPlusPlusInterface.h"
|
||||
|
||||
#ifdef TESTCPLUSPLUS
|
||||
|
||||
#include <string>
|
||||
|
||||
class Test2
|
||||
{
|
||||
std::string stringTest;
|
||||
bool done;
|
||||
public:
|
||||
void doIt();
|
||||
Test2();
|
||||
virtual ~Test2();
|
||||
};
|
||||
|
||||
#endif // TESTCPLUSPLUS
|
||||
|
||||
#endif /* MISC_TESTCPLUSPLUSBUILD_H_ */
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef MISC_TESTCPLUSPLUSINTERFACE
|
||||
#define MISC_TESTCPLUSPLUSINTERFACE
|
||||
|
||||
// #define TESTCPLUSPLUS
|
||||
|
||||
#ifdef TESTCPLUSPLUS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void test_call_cpp();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,277 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
#ifndef USE_HAL_DRIVER
|
||||
#define USE_HAL_DRIVER
|
||||
#endif
|
||||
#include "uhsdr_board.h"
|
||||
#include <stdint.h>
|
||||
#include "config_storage.h"
|
||||
#include "ui_configuration.h"
|
||||
#include "serial_eeprom.h"
|
||||
#include "uhsdr_flash.h"
|
||||
|
||||
static uint8_t config_ramcache[MAX_VAR_ADDR*2+2];
|
||||
|
||||
|
||||
#ifdef USE_CONFIGSTORAGE_FLASH
|
||||
void ConfigStorage_CopyFlash2RAMCache()
|
||||
{
|
||||
uint16_t i, data;
|
||||
|
||||
config_ramcache[0] = ts.ser_eeprom_type;
|
||||
config_ramcache[1] = ts.configstore_in_use;
|
||||
for(i=1; i <= MAX_VAR_ADDR; i++)
|
||||
{
|
||||
Flash_ReadVariable(i, &data);
|
||||
config_ramcache[i*2+1] = (uint8_t)((0x00FF)&data);
|
||||
data = data>>8;
|
||||
config_ramcache[i*2] = (uint8_t)((0x00FF)&data);
|
||||
}
|
||||
ts.configstore_in_use = CONFIGSTORE_IN_USE_RAMCACHE;
|
||||
}
|
||||
// copy data from flash storage to serial EEPROM
|
||||
void ConfigStorage_CopyFlash2Serial(void)
|
||||
{
|
||||
ConfigStorage_CopyFlash2RAMCache();
|
||||
ConfigStorage_CopyRAMCache2Serial();
|
||||
}
|
||||
|
||||
// copy data from serial to virtual EEPROM
|
||||
void ConfigStorage_CopySerial2Flash(void)
|
||||
{
|
||||
uint16_t count;
|
||||
uint16_t data;
|
||||
|
||||
for(count=1; count <= MAX_VAR_ADDR; count++)
|
||||
{
|
||||
// SerialEEPROM_ReadVariable(count, &data);
|
||||
// Flash_UpdateVariable(count, data);
|
||||
if (SerialEEPROM_ReadVariable(count, &data) == HAL_OK)
|
||||
{
|
||||
Flash_UpdateVariable(count, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* verify data serial / virtual EEPROM
|
||||
* sets ts.configstore_in_use to CONFIGSTORE_IN_USE_ERROR if
|
||||
* it encounters a difference between flash and I2C
|
||||
* Used only for debugging
|
||||
*/
|
||||
static bool ConfigStorage_CheckSameContentSerialAndFlash(void)
|
||||
{
|
||||
bool retval = true;
|
||||
for(uint16_t count=1; retval == true && count <= MAX_VAR_ADDR; count++)
|
||||
{
|
||||
uint16_t data1, data2;
|
||||
// SerialEEPROM_ReadVariable(count, &data1);
|
||||
// Flash_ReadVariable(count, &data2);
|
||||
// if(data1 != data2)
|
||||
if (SerialEEPROM_ReadVariable(count, &data1) == HAL_OK)
|
||||
{
|
||||
Flash_ReadVariable(count, &data2);
|
||||
if(data1 != data2)
|
||||
{
|
||||
retval = false;
|
||||
ts.configstore_in_use = CONFIGSTORE_IN_USE_ERROR; // mark data copy as faulty
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = false;
|
||||
// ts.configstore_in_use = CONFIGSTORE_IN_USE_ERROR; // mark data copy as faulty
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Interface for all EEPROM (ser/virt) functions and our code
|
||||
//
|
||||
// if configstore_in_use == 0 write/read to serial EEPROM,
|
||||
// if its 0xAA use data in buffer
|
||||
// otherwise use virtual EEPROM
|
||||
uint16_t ConfigStorage_ReadVariable(uint16_t addr, uint16_t *value)
|
||||
{
|
||||
uint16_t retval;
|
||||
switch(ts.configstore_in_use){
|
||||
case CONFIGSTORE_IN_USE_I2C:
|
||||
retval = SerialEEPROM_ReadVariable(addr, value);
|
||||
break;
|
||||
case CONFIGSTORE_IN_USE_FLASH:
|
||||
case SER_EEPROM_TOO_SMALL:
|
||||
retval = Flash_ReadVariable(addr, value);
|
||||
break;
|
||||
case CONFIGSTORE_IN_USE_RAMCACHE:
|
||||
{
|
||||
uint8_t lowbyte;
|
||||
uint8_t highbyte;
|
||||
uint16_t data;
|
||||
|
||||
highbyte = config_ramcache[addr*2];
|
||||
lowbyte = config_ramcache[addr*2+1];
|
||||
data = lowbyte + (highbyte<<8);
|
||||
*value = data;
|
||||
retval = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
retval = 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
//* Function Name : Write_EEPROM
|
||||
//* Object :
|
||||
//* Object :
|
||||
//* Input Parameters : addr to write to, 16 bit value as data
|
||||
//* Output Parameters : returns HAL_OK if OK, otherwise various error codes.
|
||||
//* FLASH_ERROR_OPERATION is also returned if eeprom_in_use contains bogus values.
|
||||
//* Functions called :
|
||||
//*----------------------------------------------------------------------------
|
||||
uint16_t ConfigStorage_WriteVariable(uint16_t addr, uint16_t value)
|
||||
{
|
||||
HAL_StatusTypeDef status = HAL_ERROR;
|
||||
if(ts.configstore_in_use == CONFIGSTORE_IN_USE_I2C)
|
||||
{
|
||||
SerialEEPROM_UpdateVariable(addr, value);
|
||||
status = HAL_OK;
|
||||
}
|
||||
else if(ts.configstore_in_use == CONFIGSTORE_IN_USE_FLASH)
|
||||
{
|
||||
status = (Flash_UpdateVariable(addr, value));
|
||||
}
|
||||
else if(ts.configstore_in_use == CONFIGSTORE_IN_USE_RAMCACHE)
|
||||
{
|
||||
/**
|
||||
* Was found that during saving settings,
|
||||
* first two cells was corrupted.
|
||||
* Just temp. protection...
|
||||
*/
|
||||
if ( addr == 0 )
|
||||
{
|
||||
status = HAL_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t lowbyte;
|
||||
uint8_t highbyte;
|
||||
|
||||
lowbyte = (uint8_t)((0x00FF)&value);
|
||||
highbyte = (uint8_t)((0x00FF)&(value >> 8));
|
||||
config_ramcache[addr*2] = highbyte;
|
||||
config_ramcache[addr*2+1] = lowbyte;
|
||||
status = HAL_OK;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void ConfigStorage_Init()
|
||||
{
|
||||
// virtual Eeprom init
|
||||
#ifdef USE_CONFIGSTORAGE_FLASH
|
||||
ts.ee_init_stat = Flash_Init(); // get status of EEPROM initialization
|
||||
#else
|
||||
ts.ee_init_stat = HAL_ERROR; // get status of EEPROM initialization
|
||||
#endif
|
||||
|
||||
ts.configstore_in_use = ts.ee_init_stat == HAL_OK? CONFIGSTORE_IN_USE_FLASH: CONFIGSTORE_IN_USE_ERROR;
|
||||
// at this point, we have a working flash config storage (or not)
|
||||
|
||||
ts.ser_eeprom_type = SerialEEPROM_Detect();
|
||||
|
||||
// incompatible EEPROMs, no EEPROM at all, EEPROM to small
|
||||
if(SerialEEPROM_eepromTypeDescs[ts.ser_eeprom_type].supported == true)
|
||||
{
|
||||
// we read the "in use" signature here, first we use a 16 bit value to keep the error code if any
|
||||
// this was report in #857
|
||||
uint16_t ser_eeprom_in_use = SerialEEPROM_Get_UseStateInSignature();
|
||||
|
||||
if(ser_eeprom_in_use == SER_EEPROM_NOT_IN_USE) // empty EEPROM
|
||||
{
|
||||
|
||||
#ifdef USE_CONFIGSTORAGE_FLASH
|
||||
// if we have a flash storage available, copy its contents into EEPROM
|
||||
if (ts.ee_init_stat == HAL_OK)
|
||||
{
|
||||
ts.configstore_in_use = CONFIGSTORE_IN_USE_FLASH;
|
||||
|
||||
ConfigStorage_CopyFlash2Serial(); // copy data from virtual to serial EEPROM
|
||||
ConfigStorage_CheckSameContentSerialAndFlash(); // just 4 debug purposes
|
||||
}
|
||||
#endif
|
||||
SerialEEPROM_Set_UseStateInSignature(SER_EEPROM_IN_USE); // serial EEPROM in use now
|
||||
}
|
||||
else
|
||||
{
|
||||
// if larger than 255 I2C code reported an error
|
||||
if (ser_eeprom_in_use > 0x00ff)
|
||||
{
|
||||
ts.configstore_in_use = CONFIGSTORE_IN_USE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts.configstore_in_use = CONFIGSTORE_IN_USE_I2C;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ConfigStorage_CopySerial2RAMCache()
|
||||
{
|
||||
SerialEEPROM_24Cxx_ReadBulk(0, config_ramcache, MAX_VAR_ADDR*2+2, ts.ser_eeprom_type);
|
||||
|
||||
config_ramcache[0] = ts.ser_eeprom_type;
|
||||
config_ramcache[1] = ts.configstore_in_use;
|
||||
|
||||
ts.configstore_in_use = CONFIGSTORE_IN_USE_RAMCACHE;
|
||||
}
|
||||
|
||||
uint16_t ConfigStorage_CopyRAMCache2Serial()
|
||||
{
|
||||
// we start behind the signature, which we don't want to change
|
||||
uint16_t retval = SerialEEPROM_24Cxx_WriteBulk(2, config_ramcache+2, MAX_VAR_ADDR*2, ts.ser_eeprom_type);
|
||||
if (retval == HAL_OK)
|
||||
{
|
||||
ts.configstore_in_use = CONFIGSTORE_IN_USE_I2C;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
//copy array directly to serial EEPROM
|
||||
uint16_t ConfigStorage_CopyArray2Serial(uint32_t Addr, const uint8_t *buffer, uint16_t length)
|
||||
{
|
||||
uint16_t retval = HAL_OK;
|
||||
if(ts.configstore_in_use == CONFIGSTORE_IN_USE_I2C)
|
||||
{
|
||||
retval = SerialEEPROM_24Cxx_WriteBulk(Addr, buffer, length, ts.ser_eeprom_type);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
//read array directly from serial EEPROM
|
||||
void ConfigStorage_CopySerial2Array(uint32_t Addr, uint8_t *buffer, uint16_t length)
|
||||
{
|
||||
if(ts.configstore_in_use == CONFIGSTORE_IN_USE_I2C)
|
||||
{
|
||||
SerialEEPROM_24Cxx_ReadBulk(Addr, buffer, length, ts.ser_eeprom_type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
#ifndef __CONFIG_STORAGE_H
|
||||
#define __CONFIG_STORAGE_H
|
||||
|
||||
/* Max variables number */
|
||||
#define NB_OF_VAR (0x1ff)
|
||||
|
||||
|
||||
void ConfigStorage_Init(void);
|
||||
|
||||
uint16_t ConfigStorage_ReadVariable(uint16_t addr, uint16_t *value);
|
||||
uint16_t ConfigStorage_WriteVariable(uint16_t addr, uint16_t value);
|
||||
|
||||
void ConfigStorage_CopyFlash2Serial(void);
|
||||
void ConfigStorage_CopySerial2Flash(void);
|
||||
|
||||
void ConfigStorage_CopySerial2RAMCache(void);
|
||||
uint16_t ConfigStorage_CopyRAMCache2Serial(void);
|
||||
|
||||
uint16_t ConfigStorage_CopyArray2Serial(uint32_t Addr, const uint8_t *buffer, uint16_t length);
|
||||
void ConfigStorage_CopySerial2Array(uint32_t Addr, uint8_t *buffer, uint16_t length);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
// Common
|
||||
#include "uhsdr_board.h"
|
||||
#include "profiling.h"
|
||||
|
||||
/*
|
||||
* In order to read the counters here, you'll need to connect
|
||||
* using a real-time debugger, pause execution and read values.
|
||||
* Not a big deal with ST-Link and Eclipse or gdb.
|
||||
*/
|
||||
EventProfile_t eventProfile;
|
||||
|
||||
#if 0
|
||||
// the code below is only used to ease profiling with eclipse
|
||||
// you just need hover over a variable to get the value
|
||||
void dummy() {
|
||||
|
||||
eventProfile.event[0].duration;
|
||||
eventProfile.event[0].count;
|
||||
eventProfile.event[1].duration;
|
||||
eventProfile.event[1].count;
|
||||
eventProfile.event[2].duration;
|
||||
eventProfile.event[2].count;
|
||||
eventProfile.event[3].duration;
|
||||
eventProfile.event[3].count;
|
||||
eventProfile.event[4].duration;
|
||||
eventProfile.event[4].count;
|
||||
eventProfile.event[5].duration;
|
||||
eventProfile.event[5].count;
|
||||
eventProfile.event[6].duration;
|
||||
eventProfile.event[6].count;
|
||||
eventProfile.event[7].duration;
|
||||
eventProfile.event[7].count;
|
||||
|
||||
eventProfile.event[8].duration;
|
||||
eventProfile.event[8].count;
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void profileEventsTracePrint()
|
||||
{
|
||||
#ifdef XPROFILE_EVENTS
|
||||
|
||||
for (int i = 0;i < 10;i++)
|
||||
{
|
||||
ProfilingTimedEvent* ev_ptr = profileTimedEventGet(i);
|
||||
if (ev_ptr->count != 0)
|
||||
{
|
||||
trace_printf("%d: %d uS per run\n",i, (ev_ptr->duration/(ev_ptr->count*168)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: Simple Timing Profiler **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __PROFILING_H
|
||||
#define __PROFILING_H
|
||||
|
||||
typedef enum {
|
||||
ProfileAudioInterrupt = 0,
|
||||
ProfileTP1,
|
||||
ProfileTP2,
|
||||
ProfileTP3,
|
||||
ProfileTP4,
|
||||
ProfileTP5,
|
||||
ProfileTP6,
|
||||
ProfileTP7,
|
||||
ProfileTP8,
|
||||
ProfileTP9,
|
||||
ProfileFreeDV,
|
||||
FreeDVTXUnderrun,
|
||||
EventProfileMax
|
||||
} ProfiledEventNames;
|
||||
|
||||
typedef struct {
|
||||
uint32_t count;
|
||||
uint32_t start;
|
||||
uint32_t stop;
|
||||
uint64_t duration; // to get average divide duration by count
|
||||
} ProfilingTimedEvent;
|
||||
|
||||
typedef struct {
|
||||
ProfilingTimedEvent event[EventProfileMax];
|
||||
} EventProfile_t;
|
||||
|
||||
extern EventProfile_t eventProfile;
|
||||
|
||||
#define PROFILE_EVENTS
|
||||
inline void profileEvent(const ProfiledEventNames pe) {
|
||||
#ifdef PROFILE_EVENTS
|
||||
if (pe<EventProfileMax) {
|
||||
eventProfile.event[pe].count++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* How to use:
|
||||
* First start the cycle timer with profileTimeEventInit()
|
||||
* This resets the timer and makes it run.
|
||||
*
|
||||
* At any time call profileTimedEventStart(EventName)
|
||||
* to have the start being recorded
|
||||
* at the end of the event call profileTimedEventStop(EventName)
|
||||
* Duration of a single event should not be longer then 2^32 / clock frequency
|
||||
* i.e. ~25s @168 Mhz for a single event
|
||||
* total duration recorded should not be more than 2^64 cycles
|
||||
* which is quite a lot, i.e. there is no limit on that for the
|
||||
* average person in this universe
|
||||
*
|
||||
* Due to the approach multiple events can be recorded correctly but
|
||||
* outer events include the overhead of the calculation of the duration
|
||||
* only the innermost events are more or less accurate unless you time the profile functions and
|
||||
* remove the overhead later.
|
||||
*/
|
||||
|
||||
void profileEventsTracePrint(void);
|
||||
|
||||
|
||||
//inline void profileTimedEventInit(void);
|
||||
//inline void profileTimedEventStart(const ProfiledEventNames pe);
|
||||
//inline void profileTimedEventStop(const ProfiledEventNames pe);
|
||||
//inline void profileTimedEventReset(const ProfiledEventNames pe);
|
||||
//inline ProfilingTimedEvent* profileTimedEventGet(const ProfiledEventNames pe);
|
||||
|
||||
|
||||
// INLINE IMPLEMENTATIONS
|
||||
|
||||
#define DWT_CYCCNT ((volatile uint32_t *)0xE0001004)
|
||||
#define DWT_CONTROL ((volatile uint32_t *)0xE0001000)
|
||||
#define SCB_DEMCR ((volatile uint32_t *)0xE000EDFC)
|
||||
#define DWT_LAR ((volatile uint32_t *)0xE0001FB0)
|
||||
|
||||
//inline void profileCycleCount_reset(void){
|
||||
static inline void profileCycleCount_reset(){
|
||||
*SCB_DEMCR |= 0x01000000;
|
||||
#ifdef STM32F7
|
||||
*DWT_LAR = 0xC5ACCE55; // <-- added unlock access to DWT (ITM, etc.)registers
|
||||
#endif
|
||||
*DWT_CYCCNT = 0; // reset the counter
|
||||
*DWT_CONTROL = 0;
|
||||
}
|
||||
|
||||
//inline void profileCycleCount_start(void)
|
||||
static inline void profileCycleCount_start()
|
||||
{
|
||||
*DWT_CONTROL = *DWT_CONTROL | 1;
|
||||
}
|
||||
|
||||
//inline void profileCycleCount_stop(void)
|
||||
static inline void profileCycleCount_stop(void)
|
||||
{
|
||||
*DWT_CONTROL = *DWT_CONTROL & ~1; //
|
||||
}
|
||||
|
||||
//inline uint32_t profileCycleCount_get(void)
|
||||
static inline uint32_t profileCycleCount_get(void)
|
||||
{
|
||||
return *DWT_CYCCNT;
|
||||
}
|
||||
|
||||
//inline void profileTimedEventInit(void)
|
||||
static inline void profileTimedEventInit(void)
|
||||
{
|
||||
profileCycleCount_reset();
|
||||
profileCycleCount_start();
|
||||
}
|
||||
|
||||
//inline void profileTimedEventStart(const ProfiledEventNames pe)
|
||||
static inline void profileTimedEventStart(const ProfiledEventNames pe)
|
||||
{
|
||||
#ifdef PROFILE_EVENTS
|
||||
if (pe<EventProfileMax) {
|
||||
eventProfile.event[pe].start = profileCycleCount_get();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
//inline void profileTimedEventStop(const ProfiledEventNames pe)
|
||||
static inline void profileTimedEventStop(const ProfiledEventNames pe)
|
||||
{
|
||||
|
||||
#ifdef PROFILE_EVENTS
|
||||
uint32_t stop = profileCycleCount_get();
|
||||
if (pe<EventProfileMax) {
|
||||
eventProfile.event[pe].stop = stop;
|
||||
eventProfile.event[pe].count++;
|
||||
eventProfile.event[pe].duration += (eventProfile.event[pe].stop-eventProfile.event[pe].start);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
//inline void profileTimedEventReset(const ProfiledEventNames pe)
|
||||
static inline void profileTimedEventReset(const ProfiledEventNames pe)
|
||||
{
|
||||
#ifdef PROFILE_EVENTS
|
||||
if (pe<EventProfileMax) {
|
||||
eventProfile.event[pe].start = 0;
|
||||
eventProfile.event[pe].stop = 0;
|
||||
eventProfile.event[pe].count = 0;
|
||||
eventProfile.event[pe].duration = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//inline ProfilingTimedEvent* profileTimedEventGet(const ProfiledEventNames pe)
|
||||
static inline ProfilingTimedEvent* profileTimedEventGet(const ProfiledEventNames pe)
|
||||
{
|
||||
ProfilingTimedEvent* pe_ptr = NULL;
|
||||
#ifdef PROFILE_EVENTS
|
||||
if (pe<EventProfileMax) {
|
||||
pe_ptr = &eventProfile.event[pe];
|
||||
}
|
||||
#endif
|
||||
return pe_ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,620 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
// Common
|
||||
#include "uhsdr_board.h"
|
||||
#include "uhsdr_hw_i2c.h"
|
||||
|
||||
#include "serial_eeprom.h"
|
||||
|
||||
// for MAX_VAR_ADDR only
|
||||
#include "ui_configuration.h"
|
||||
|
||||
typedef struct SerialEEPROM_Configuration
|
||||
{
|
||||
uint8_t device_type;
|
||||
uint8_t use_type;
|
||||
bool detection;
|
||||
} SerialEEPROM_Configuration_t;
|
||||
|
||||
// static SerialEEPROM_Configuration_t ser_eeprom_config;
|
||||
|
||||
const SerialEEPROM_EEPROMTypeDescriptor SerialEEPROM_eepromTypeDescs[SERIAL_EEPROM_DESC_NUM] = {
|
||||
// 0
|
||||
{
|
||||
.size = 0,
|
||||
.supported = false,
|
||||
.pagesize = 0,
|
||||
.name = "No EEPROM"
|
||||
},
|
||||
// 1
|
||||
{
|
||||
.size = 0,
|
||||
.supported = false,
|
||||
.pagesize = 0,
|
||||
.name = "Wrong Signature"
|
||||
},
|
||||
// 2
|
||||
{
|
||||
.size = 0,
|
||||
.supported = false,
|
||||
.pagesize = 0,
|
||||
.name = "Unknown Type"
|
||||
},
|
||||
// 3
|
||||
{
|
||||
.size = 0,
|
||||
.supported = false,
|
||||
.pagesize = 0,
|
||||
.name = "Not used"
|
||||
},
|
||||
// 4
|
||||
{
|
||||
.size = 0,
|
||||
.supported = false,
|
||||
.pagesize = 64,
|
||||
.name = "Not used"
|
||||
},
|
||||
// 5
|
||||
{
|
||||
.size = 0,
|
||||
.supported = false,
|
||||
.pagesize = 0,
|
||||
.name = "Not used"
|
||||
},
|
||||
// 6
|
||||
{
|
||||
.size = 0,
|
||||
.supported = false,
|
||||
.pagesize = 0,
|
||||
.name = "Not used"
|
||||
},
|
||||
// 7
|
||||
{
|
||||
.size = 128,
|
||||
.supported = false,
|
||||
.pagesize = 8,
|
||||
.name = "24xx01"
|
||||
},
|
||||
// 8
|
||||
{
|
||||
.size = 256,
|
||||
.supported = false,
|
||||
.pagesize = 8,
|
||||
.name = "24xx02"
|
||||
},
|
||||
// 9
|
||||
{
|
||||
.size = 2*256,
|
||||
.supported = false,
|
||||
.pagesize = 16,
|
||||
.name = "24xx04"
|
||||
},
|
||||
// 10
|
||||
{
|
||||
.size = 1*1024,
|
||||
.supported = false,
|
||||
.pagesize = 16,
|
||||
.name = "24xx08"
|
||||
},
|
||||
// 11
|
||||
{
|
||||
.size = 2*1024,
|
||||
.supported = false,
|
||||
.pagesize = 16,
|
||||
.name = "24xx16"
|
||||
},
|
||||
// 12
|
||||
{
|
||||
.size = 4*1024,
|
||||
.supported = false,
|
||||
.pagesize = 32,
|
||||
.name = "24xx32"
|
||||
},
|
||||
// 13
|
||||
{
|
||||
.size = 8*1024,
|
||||
.supported = false,
|
||||
.pagesize = 32,
|
||||
.name = "24xx64"
|
||||
},
|
||||
// 14
|
||||
{
|
||||
.size = 16*1024,
|
||||
.supported = false,
|
||||
.pagesize = 64,
|
||||
.name = "24xx128"
|
||||
},
|
||||
// 15
|
||||
{
|
||||
.size = 32*1024,
|
||||
.supported = true,
|
||||
.pagesize = 64,
|
||||
.name = "24xx256"
|
||||
},
|
||||
// 16
|
||||
{
|
||||
.size = 64*1024,
|
||||
.supported = true,
|
||||
.pagesize = 128,
|
||||
.name = "24xx512"
|
||||
},
|
||||
// 17
|
||||
{
|
||||
.size = 128*1024,
|
||||
.supported = true,
|
||||
.pagesize = 128,
|
||||
.name = "24xx1025"
|
||||
},
|
||||
// 18
|
||||
{
|
||||
.size = 128 * 1024,
|
||||
.supported = true,
|
||||
.pagesize = 128,
|
||||
.name = "24xx1026/CM01"
|
||||
},
|
||||
// 19
|
||||
{
|
||||
.size = 256*1024,
|
||||
.supported = true,
|
||||
.pagesize = 256,
|
||||
.name = "24CM02"
|
||||
}
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t devaddr;
|
||||
uint16_t addr;
|
||||
uint16_t addr_size;
|
||||
} SerialEEPROM_24CXX_Descriptor;
|
||||
|
||||
static SerialEEPROM_24CXX_Descriptor serialEeprom_desc;
|
||||
// THIS CAN BE USED ONLY WITH SINGLE EEPROM AND SINGLE THREAD
|
||||
// NOT THREAD SAFE, USE local variable instead then
|
||||
|
||||
|
||||
|
||||
#define MEM_DEVICE_WRITE_ADDR 0xA0
|
||||
// serial eeprom functions by DF8OE
|
||||
|
||||
static uint16_t SerialEEPROM_24Cxx_DeviceConnected(void)
|
||||
{
|
||||
uint16_t retVal = UhsdrHw_I2C_DeviceReady(&hi2c2,MEM_DEVICE_WRITE_ADDR);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
static void SerialEEPROM_24Cxx_AdjustAddrs(const uint8_t Mem_Type, uint8_t* devaddr_ptr, uint32_t* Addr_ptr)
|
||||
{
|
||||
|
||||
*devaddr_ptr = MEM_DEVICE_WRITE_ADDR;
|
||||
|
||||
if (*Addr_ptr > 0xFFFF) {
|
||||
switch (Mem_Type)
|
||||
{
|
||||
case 17: // 24LC1025
|
||||
*devaddr_ptr = MEM_DEVICE_WRITE_ADDR + 8; // 24LC1025
|
||||
break;
|
||||
case 18:
|
||||
*devaddr_ptr = MEM_DEVICE_WRITE_ADDR + 2; // 24LC1026
|
||||
break;
|
||||
case 19: // 24CM02
|
||||
*devaddr_ptr = MEM_DEVICE_WRITE_ADDR + ((*Addr_ptr & 0x30000) >> 15); // the upper bits 16 and 17 determine the I2C address offset
|
||||
break;
|
||||
}
|
||||
*Addr_ptr &= 0xFFFF; // mask address to 16bits in all cases
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t SerialEEPROM_24Cxx_ackPolling(uint32_t Addr, uint8_t Mem_Type)
|
||||
{
|
||||
uint8_t devaddr;
|
||||
|
||||
SerialEEPROM_24Cxx_AdjustAddrs(Mem_Type,&devaddr,&Addr);
|
||||
|
||||
uint16_t retVal = UhsdrHw_I2C_DeviceReady(&hi2c2,devaddr); // != HAL_OK?0xFD00:0;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static void SerialEEPROM_24Cxx_StartTransfer_Prep(uint32_t Addr, uint8_t Mem_Type, SerialEEPROM_24CXX_Descriptor* eeprom_desc_ptr)
|
||||
{
|
||||
SerialEEPROM_24Cxx_AdjustAddrs(Mem_Type,&eeprom_desc_ptr->devaddr,&Addr);
|
||||
|
||||
eeprom_desc_ptr->addr = (uint16_t)((0xFFFF)&(Addr));
|
||||
if (Mem_Type > 8)
|
||||
{
|
||||
eeprom_desc_ptr->addr_size = I2C_MEMADD_SIZE_16BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
eeprom_desc_ptr->addr_size = I2C_MEMADD_SIZE_8BIT;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t SerialEEPROM_24Cxx_Write(uint32_t Addr, uint8_t Data, uint8_t Mem_Type)
|
||||
{
|
||||
SerialEEPROM_24Cxx_StartTransfer_Prep(Addr, Mem_Type,&serialEeprom_desc);
|
||||
uint16_t retVal = UhsdrHw_I2C_WriteRegister(SERIALEEPROM_I2C,serialEeprom_desc.devaddr,serialEeprom_desc.addr,serialEeprom_desc.addr_size,Data);
|
||||
|
||||
if (!retVal)
|
||||
{
|
||||
retVal = SerialEEPROM_24Cxx_ackPolling(Addr,Mem_Type);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
uint16_t SerialEEPROM_24Cxx_Read(uint32_t Addr, uint8_t Mem_Type)
|
||||
{
|
||||
uint8_t value;
|
||||
SerialEEPROM_24Cxx_StartTransfer_Prep(Addr, Mem_Type,&serialEeprom_desc);
|
||||
uint16_t retVal = UhsdrHw_I2C_ReadRegister(SERIALEEPROM_I2C,serialEeprom_desc.devaddr,serialEeprom_desc.addr,serialEeprom_desc.addr_size,&value);
|
||||
if (!retVal)
|
||||
{
|
||||
retVal = value;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
uint16_t SerialEEPROM_24Cxx_ReadBulk(uint32_t Addr, uint8_t *buffer, uint16_t length, uint8_t Mem_Type)
|
||||
{
|
||||
uint16_t retVal = 0xFFFF;
|
||||
if (Mem_Type < SERIAL_EEPROM_DESC_NUM) {
|
||||
uint32_t page, count;
|
||||
count = 0;
|
||||
|
||||
page =SerialEEPROM_eepromTypeDescs[Mem_Type].pagesize;
|
||||
|
||||
while(count < length)
|
||||
{
|
||||
if (length - count < page)
|
||||
{
|
||||
// make sure we do not read more than asked for! Buffer Overflow!
|
||||
page = (length - count);
|
||||
}
|
||||
SerialEEPROM_24Cxx_StartTransfer_Prep(Addr + count, Mem_Type,&serialEeprom_desc);
|
||||
retVal = UhsdrHw_I2C_ReadBlock(SERIALEEPROM_I2C,serialEeprom_desc.devaddr,serialEeprom_desc.addr,serialEeprom_desc.addr_size,&buffer[count],page);
|
||||
count+=page;
|
||||
if (retVal)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a consecutive area of memory into the I2C eeprom starting with Addr.
|
||||
* @param Addr the location of the first byte in the eeprom. May have any value within the memory size of the eeprom
|
||||
* @param buffer memory to copy from
|
||||
* @param length how many bytes to copy
|
||||
* @param Mem_Type which eeprom type are we having
|
||||
* @return 0 if success, I2C error code otherwise
|
||||
*/
|
||||
uint16_t SerialEEPROM_24Cxx_WriteBulk(uint32_t Addr, const uint8_t *buffer, uint16_t length, uint8_t Mem_Type)
|
||||
{
|
||||
uint16_t retVal = 0;
|
||||
if (Mem_Type < SERIAL_EEPROM_DESC_NUM) {
|
||||
uint32_t count = 0;
|
||||
|
||||
const uint32_t page = SerialEEPROM_eepromTypeDescs[Mem_Type].pagesize;
|
||||
|
||||
|
||||
while(retVal == 0 && count < length)
|
||||
{
|
||||
SerialEEPROM_24Cxx_StartTransfer_Prep(Addr + count, Mem_Type,&serialEeprom_desc);
|
||||
|
||||
uint32_t transfer_size = page;
|
||||
|
||||
// correct the transfer_size to keep inside a single page
|
||||
// if the start address is not on a page boundary
|
||||
// this will happen only for the first bulkd write (if at all)
|
||||
// then the Addr + count will be aligned on page boundaries
|
||||
|
||||
transfer_size -= ((Addr+count) % page);
|
||||
|
||||
if (length - count < transfer_size)
|
||||
{
|
||||
transfer_size = length - count;
|
||||
}
|
||||
|
||||
retVal = UhsdrHw_I2C_WriteBlock(SERIALEEPROM_I2C,serialEeprom_desc.devaddr,serialEeprom_desc.addr,serialEeprom_desc.addr_size,&buffer[count],transfer_size);
|
||||
count+=transfer_size;
|
||||
if (retVal)
|
||||
{
|
||||
break;
|
||||
}
|
||||
retVal = SerialEEPROM_24Cxx_ackPolling(Addr,Mem_Type);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief in general a non-destructive probing to identify the used EEPROM, in some cases devices are written (and changed data restored)
|
||||
* this code uses hardware properties to identify the connected I2C eeprom, no previously signature etc. used or required
|
||||
* @returns identified eeprom chip type or EEPROM_SER_UNKNOWN
|
||||
*/
|
||||
static uint8_t SerialEEPROM_24Cxx_DetectProbeHardware(void)
|
||||
{
|
||||
uint8_t ser_eeprom_type = EEPROM_SER_UNKNOWN;
|
||||
|
||||
const uint8_t testsignatureA = 0x66;
|
||||
const uint8_t testsignatureB = 0x77; // has to be different from testsignature 1
|
||||
|
||||
const uint16_t testaddr1 = 0x0001;
|
||||
const uint16_t testaddr1plus128 = testaddr1 + 0x80;
|
||||
|
||||
// 8 Bit Test First
|
||||
uint16_t test8Byte1 = SerialEEPROM_24Cxx_Read(testaddr1,8);
|
||||
|
||||
|
||||
// first decide if 8 or 16 bit addressable eeprom by trying to read with 8 or 16 bit algorithm
|
||||
// if an algorithm succeeds we know the address width
|
||||
if(test8Byte1 < 0x100)
|
||||
{
|
||||
// 8 bit addressing
|
||||
uint16_t test8Byte2 = SerialEEPROM_24Cxx_Read(testaddr1plus128,8);
|
||||
|
||||
SerialEEPROM_24Cxx_Write(testaddr1,testsignatureB,8);
|
||||
SerialEEPROM_24Cxx_Write(testaddr1plus128,testsignatureB,8);
|
||||
|
||||
if (SerialEEPROM_24Cxx_Read(testaddr1,8) == testsignatureB)
|
||||
{
|
||||
SerialEEPROM_24Cxx_Write(testaddr1,testsignatureA,8); // write test signature
|
||||
ser_eeprom_type = 7; // smallest possible 8 bit EEPROM (128Bytes)
|
||||
if(SerialEEPROM_24Cxx_Read(testaddr1plus128,8) == testsignatureB)
|
||||
{
|
||||
ser_eeprom_type = 8;
|
||||
}
|
||||
}
|
||||
SerialEEPROM_24Cxx_Write(testaddr1,test8Byte1,8); // write back old data
|
||||
SerialEEPROM_24Cxx_Write(testaddr1plus128,test8Byte2,8);
|
||||
}
|
||||
if (ser_eeprom_type == EEPROM_SER_UNKNOWN)
|
||||
{
|
||||
// 16 bit addressing check
|
||||
// the other banks are mapped to different I2C
|
||||
// device addresses. We simply try to read from them
|
||||
// and if it succeeds we know the device type
|
||||
// We need to check unique addresses for each EEPROM type
|
||||
// 0xA0 + 0x10000: 0xA8
|
||||
if(SerialEEPROM_24Cxx_Read(0x10000,17) < 0x100)
|
||||
{
|
||||
ser_eeprom_type = 17; // 24LC1025
|
||||
}
|
||||
// 0xA0 + 0x10000: 0xA2
|
||||
if(SerialEEPROM_24Cxx_Read(0x10000,18) < 0x100)
|
||||
{
|
||||
ser_eeprom_type = 18; // 24LC1026
|
||||
}
|
||||
// 0xA0 + 0x10000: 0xA2 + 0x20000: 0xA4 + 0x30000: 0xA6
|
||||
if(SerialEEPROM_24Cxx_Read(0x20000,19) < 0x100)
|
||||
{
|
||||
ser_eeprom_type = 19; // 24CM02
|
||||
}
|
||||
|
||||
// it is not a large EEPROM (i.e. >64KB Data)
|
||||
//
|
||||
// the following test requires writing to EEPROM,
|
||||
// we remember content of test locations
|
||||
// and write them back later
|
||||
if(ser_eeprom_type == EEPROM_SER_UNKNOWN)
|
||||
{
|
||||
const uint16_t testaddr1plus256 = 0x0100 + testaddr1; // same as before but 0x100 == 256 byte spacing
|
||||
uint16_t testByte1 = SerialEEPROM_24Cxx_Read(testaddr1,16); // read old content
|
||||
uint16_t testByte2 = SerialEEPROM_24Cxx_Read(testaddr1plus256,16); // of test bytes
|
||||
|
||||
if (testByte1 < 0x100 && testByte2 < 0x100) {
|
||||
|
||||
// successful read from both locations, let us start
|
||||
SerialEEPROM_24Cxx_Write(testaddr1, testsignatureA,16); // write testsignature 1
|
||||
SerialEEPROM_24Cxx_Write(testaddr1plus256, testsignatureB,16); // write testsignature 2
|
||||
if(SerialEEPROM_24Cxx_Read(testaddr1,16) == testsignatureA && SerialEEPROM_24Cxx_Read(testaddr1plus256,16) == testsignatureB)
|
||||
{
|
||||
// 16 bit addressing
|
||||
ser_eeprom_type = 9; // smallest possible 16 bit EEPROM
|
||||
|
||||
// we look for the "looping" in data, i.e. we read back 0x66
|
||||
// which we wrote to address 0x0003
|
||||
// from a address we did not wrote it to
|
||||
// once it occurs, we know the size of the EEPROM
|
||||
// since all of these EEPROMS are ignoring the unused bits in the address
|
||||
for (int shift = 0; shift < 8; shift++) {
|
||||
uint16_t shift_test_addr = (0x200 << shift)+testaddr1;
|
||||
if(SerialEEPROM_24Cxx_Read(shift_test_addr,16) == testsignatureA) {
|
||||
// now we write test signature 2 to make sure the match was no accident
|
||||
// i.e. match with same content in EEPROM
|
||||
SerialEEPROM_24Cxx_Write(shift_test_addr,testsignatureB,16);
|
||||
if(SerialEEPROM_24Cxx_Read(testaddr1,16) == testsignatureB) {
|
||||
// we found the looping,
|
||||
// now stop checking and set EEPROM type
|
||||
ser_eeprom_type = 9 + shift;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// oops: just an accident, so we write back old content and continue
|
||||
SerialEEPROM_24Cxx_Write(shift_test_addr,testsignatureA,16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
SerialEEPROM_24Cxx_Write(testaddr1,testByte1,16); // write back old data
|
||||
SerialEEPROM_24Cxx_Write(testaddr1plus256,testByte2,16);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ser_eeprom_type;
|
||||
}
|
||||
|
||||
static void SerialEEPROM_Read_Signature(uint8_t ser_eeprom_type, uint16_t* type_p, uint16_t* state_p)
|
||||
{
|
||||
*type_p = SerialEEPROM_24Cxx_Read(0,ser_eeprom_type);
|
||||
*state_p = SerialEEPROM_24Cxx_Read(1,ser_eeprom_type);
|
||||
}
|
||||
|
||||
uint16_t SerialEEPROM_Set_UseStateInSignature(uint8_t state)
|
||||
{
|
||||
return SerialEEPROM_24Cxx_Write(1,SER_EEPROM_IN_USE,ts.ser_eeprom_type);
|
||||
}
|
||||
|
||||
uint16_t SerialEEPROM_Get_UseStateInSignature()
|
||||
{
|
||||
return SerialEEPROM_24Cxx_Read(1,ts.ser_eeprom_type);
|
||||
}
|
||||
|
||||
uint8_t SerialEEPROM_Detect() {
|
||||
|
||||
uint16_t ser_eeprom_type = EEPROM_SER_UNKNOWN;
|
||||
|
||||
// serial EEPROM init
|
||||
if(SerialEEPROM_24Cxx_DeviceConnected() != HAL_OK || SerialEEPROM_24xx_Exists() == false) // Issue with Ser EEPROM, either not available or other problems
|
||||
{
|
||||
ser_eeprom_type = EEPROM_SER_NONE; // no serial EEPROM available
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// this initial read will bring us the first byte of any eeprom (8 or 16bits)
|
||||
// if we read anything but the 0xff == SER_EERPM_NOT_IN_USE value which indicates empty eeprom
|
||||
// we assume some configuration information tells us what EEPROM we have and how it is used
|
||||
if(SerialEEPROM_24Cxx_Read(0,16) != SER_EEPROM_NOT_IN_USE)
|
||||
{
|
||||
ser_eeprom_type = EEPROM_SER_WRONG_SIG;
|
||||
|
||||
// unless we find a correct signature, we have to assume the EEPROM has incorrect/corrupted data
|
||||
|
||||
uint16_t ser_eeprom_type_read;
|
||||
uint16_t ser_eeprom_sig;
|
||||
|
||||
SerialEEPROM_Read_Signature(8, &ser_eeprom_type_read, &ser_eeprom_sig);
|
||||
|
||||
// all 8 bit (i.e. 256 or 128 Byte) EEPROMS are marked as "too small" during detection
|
||||
if(ser_eeprom_sig == SER_EEPROM_TOO_SMALL && ser_eeprom_type_read >= SERIAL_EEPROM_DESC_REAL && ser_eeprom_type_read < 9)
|
||||
{
|
||||
ser_eeprom_type = ser_eeprom_type_read;
|
||||
}
|
||||
else
|
||||
{
|
||||
SerialEEPROM_Read_Signature(16, &ser_eeprom_type_read, &ser_eeprom_sig);
|
||||
|
||||
// we either have a new EEPROM, just being initialized ( ser_eeprom_sig = SER_EEPROM_NOT_IN_USE && valid type) or
|
||||
// we have an used EEPROM (ser_eeprom_sig = SER_EEPROM_IN_USE && valid type)
|
||||
// please note, that even though no 16 bit EEPROM gets the "too small" signature written in, these may still be
|
||||
// consider too small by the later code. Only EEPROMS which have the "supported" flag set in the descriptor will
|
||||
// be consider of sufficient size for actual use
|
||||
if((ser_eeprom_sig == SER_EEPROM_IN_USE || ser_eeprom_sig == SER_EEPROM_NOT_IN_USE) && ser_eeprom_type_read < SERIAL_EEPROM_DESC_NUM && ser_eeprom_type_read > 8)
|
||||
{
|
||||
ser_eeprom_type = ser_eeprom_type_read;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ser_eeprom_type = SerialEEPROM_24Cxx_DetectProbeHardware();
|
||||
|
||||
if (ser_eeprom_type >= SERIAL_EEPROM_DESC_REAL && ser_eeprom_type < SERIAL_EEPROM_DESC_NUM)
|
||||
{
|
||||
SerialEEPROM_24Cxx_Write(0,ser_eeprom_type,ser_eeprom_type);
|
||||
if (SerialEEPROM_eepromTypeDescs[ser_eeprom_type].supported == false)
|
||||
{
|
||||
SerialEEPROM_24Cxx_Write(1,SER_EEPROM_TOO_SMALL,ser_eeprom_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
// just to be save. Never ever deliver a type id outside the array boundaries.
|
||||
if (ser_eeprom_type >= SERIAL_EEPROM_DESC_NUM)
|
||||
{
|
||||
ser_eeprom_type = EEPROM_SER_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
return ser_eeprom_type;
|
||||
|
||||
}
|
||||
|
||||
static void SerialEEPROM_Clear_Variable(uint16_t addr)
|
||||
{
|
||||
const uint8_t empty_var[2] = { 0xff, 0xff };
|
||||
SerialEEPROM_24Cxx_WriteBulk(addr*2, empty_var,2, ts.ser_eeprom_type);
|
||||
}
|
||||
|
||||
void SerialEEPROM_Clear_AllVariables()
|
||||
{
|
||||
// variable 0 is the reserved signature variable
|
||||
for(uint16_t count=1; count <= MAX_VAR_ADDR; count++)
|
||||
{
|
||||
SerialEEPROM_Clear_Variable(count);
|
||||
}
|
||||
}
|
||||
|
||||
void SerialEEPROM_Clear_Signature()
|
||||
{
|
||||
// variable 0 is the reserved signature variable
|
||||
ts.ser_eeprom_type = SerialEEPROM_24Cxx_DetectProbeHardware();
|
||||
SerialEEPROM_Clear_Variable(0);
|
||||
}
|
||||
|
||||
|
||||
bool SerialEEPROM_24xx_Exists()
|
||||
{
|
||||
return SerialEEPROM_24Cxx_Read(0,8) < 0x100;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Interface for serial EEPROM functions
|
||||
//
|
||||
uint16_t SerialEEPROM_ReadVariable(uint16_t addr, uint16_t *value) // reference to serial EEPROM read function
|
||||
{
|
||||
uint8_t bytes[2];
|
||||
|
||||
|
||||
uint16_t retval = SerialEEPROM_24Cxx_ReadBulk(addr*2,bytes, 2, ts.ser_eeprom_type);
|
||||
|
||||
if (retval == HAL_OK)
|
||||
{
|
||||
*value = ((uint16_t)bytes[0])<<8;
|
||||
*value |= bytes[1];
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint16_t SerialEEPROM_UpdateVariable(uint16_t addr, uint16_t value)
|
||||
{
|
||||
uint16_t value_read = 0;
|
||||
uint16_t retval = SerialEEPROM_ReadVariable(addr,&value_read);
|
||||
if (retval != 0 || value_read != value )
|
||||
{
|
||||
retval = SerialEEPROM_WriteVariable(addr,value);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint16_t SerialEEPROM_WriteVariable(uint16_t addr, uint16_t value) // reference to serial EEPROM write function, writing unsigned 16 bit
|
||||
{
|
||||
uint8_t bytes[2];
|
||||
|
||||
bytes[0] = (uint8_t)((value&(0xFF00))>>8);
|
||||
bytes[1] = (uint8_t)(value&(0x00FF));
|
||||
|
||||
return SerialEEPROM_24Cxx_WriteBulk(addr*2, bytes, 2, ts.ser_eeprom_type);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** mcHF QRP Transceiver **
|
||||
** K Atanassov - M0NKA 2014 **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** File name: **
|
||||
** Description: Serial EEPROM Functions by DF8OE **
|
||||
** Last Modified: **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
|
||||
#ifndef __SERIAL_EEPROM_H
|
||||
#define __SERIAL_EEPROM_H
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t size; // in Bytes
|
||||
bool supported; // i.e. big enough to be used
|
||||
uint16_t pagesize; // in Bytes
|
||||
const char* name;
|
||||
} SerialEEPROM_EEPROMTypeDescriptor;
|
||||
|
||||
#define SERIAL_EEPROM_DESC_NUM 20
|
||||
#define SERIAL_EEPROM_DESC_REAL 7
|
||||
// the first type number not used as pseudo device (24xx128)
|
||||
#define SERIAL_EEPROM_MIN_USEABLE_SIZE 32*1024
|
||||
|
||||
// WE CANNOT CHANGE THESE CODES AS THIS WILL BREAK EXISTING CONFIGURATIONS STORED IN EEPROM
|
||||
#define SER_EEPROM_IN_USE 0x00
|
||||
#define SER_EEPROM_NOT_IN_USE 0xFF
|
||||
#define SER_EEPROM_TOO_SMALL 0x10
|
||||
|
||||
|
||||
|
||||
extern const SerialEEPROM_EEPROMTypeDescriptor SerialEEPROM_eepromTypeDescs[SERIAL_EEPROM_DESC_NUM];
|
||||
|
||||
|
||||
// low level interface
|
||||
bool SerialEEPROM_24xx_Exists(void);
|
||||
uint16_t SerialEEPROM_24Cxx_Write(uint32_t, uint8_t, uint8_t);
|
||||
uint16_t SerialEEPROM_24Cxx_Read(uint32_t, uint8_t);
|
||||
uint16_t SerialEEPROM_24Cxx_WriteBulk(uint32_t, const uint8_t*, uint16_t, uint8_t);
|
||||
uint16_t SerialEEPROM_24Cxx_ReadBulk(uint32_t, uint8_t*, uint16_t, uint8_t);
|
||||
|
||||
uint16_t SerialEEPROM_ReadVariable(uint16_t addr, uint16_t *value);
|
||||
uint16_t SerialEEPROM_WriteVariable(uint16_t addr, uint16_t value);
|
||||
uint16_t SerialEEPROM_UpdateVariable(uint16_t addr, uint16_t value);
|
||||
|
||||
uint8_t SerialEEPROM_Detect(void);
|
||||
uint16_t SerialEEPROM_Set_UseStateInSignature(uint8_t state);
|
||||
uint16_t SerialEEPROM_Get_UseStateInSignature(void);
|
||||
void SerialEEPROM_Clear_Signature(void);
|
||||
void SerialEEPROM_Clear_AllVariables(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,367 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: tfdmdv.c
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: April 16 2012
|
||||
|
||||
Tests for the C version of the FDMDV modem. This program outputs a
|
||||
file of Octave vectors that are loaded and automatically tested
|
||||
against the Octave version of the modem by the Octave script
|
||||
tfmddv.m
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2012 David Rowe
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License version 2, as
|
||||
published by the Free Software Foundation. This program 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 General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "fdmdv_internal.h"
|
||||
#include "codec2_fdmdv.h"
|
||||
#include "octave.h"
|
||||
|
||||
|
||||
#ifdef ARM_MATH_CM4
|
||||
#include "Trace.h"
|
||||
#define FPRINTF(f,...) trace_printf(__VA_ARGS__)
|
||||
#else
|
||||
#define FPRINTF(...) fprintf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#include "profiling.h"
|
||||
|
||||
|
||||
// 0 -> each frame is stored separately
|
||||
// 1 -> after all frames store all data, this is currently required for
|
||||
// octave analysis
|
||||
#define CUMULATIVE 0
|
||||
|
||||
// 0 -> Minimal memory consumption, can be run on targets with little memory
|
||||
// 1 -> normal memory consumption, this is currently required for
|
||||
// octave analisys
|
||||
#define MULTIFRAME 0
|
||||
|
||||
|
||||
#if MULTIFRAME
|
||||
#define FRAMERUNS 1 // number of runs
|
||||
#define FRAMES 35 // allocate space for n frames
|
||||
#define FRAMEINCR 35 // number of frames to process per run
|
||||
#else
|
||||
#define FRAMERUNS 35
|
||||
#define FRAMES 1
|
||||
#define FRAMEINCR 1
|
||||
#endif
|
||||
|
||||
#define CHANNEL_BUF_SIZE (10*M_FAC)
|
||||
FILE *fout;
|
||||
struct FDMDV *fdmdv;
|
||||
|
||||
extern float pilot_coeff[];
|
||||
float channel[CHANNEL_BUF_SIZE];
|
||||
int channel_count;
|
||||
|
||||
int run(int cumulativeOutput, int numberOfRuns, int currentRun, int next_nin)
|
||||
{
|
||||
int tx_bits[FDMDV_BITS_PER_FRAME];
|
||||
COMP tx_symbols[FDMDV_NC+1];
|
||||
COMP tx_fdm[M_FAC];
|
||||
COMP rx_fdm[M_FAC+M_FAC/P];
|
||||
float foff_coarse;
|
||||
int nin;
|
||||
COMP rx_fdm_fcorr[M_FAC+M_FAC/P];
|
||||
COMP rx_fdm_filter[M_FAC+M_FAC/P];
|
||||
COMP rx_filt[NC+1][P+1];
|
||||
float rx_timing;
|
||||
float env[NT*P];
|
||||
COMP rx_symbols[FDMDV_NC+1];
|
||||
int rx_bits[FDMDV_BITS_PER_FRAME];
|
||||
float foff_fine;
|
||||
int sync_bit, reliable_sync_bit;
|
||||
|
||||
int tx_bits_log[FDMDV_BITS_PER_FRAME*FRAMES];
|
||||
COMP tx_symbols_log[(FDMDV_NC+1)*FRAMES];
|
||||
COMP tx_fdm_log[M_FAC*FRAMES];
|
||||
COMP pilot_baseband1_log[NPILOTBASEBAND*FRAMES];
|
||||
COMP pilot_baseband2_log[NPILOTBASEBAND*FRAMES];
|
||||
COMP pilot_lpf1_log[NPILOTLPF*FRAMES];
|
||||
COMP pilot_lpf2_log[NPILOTLPF*FRAMES];
|
||||
COMP S1_log[MPILOTFFT*FRAMES];
|
||||
COMP S2_log[MPILOTFFT*FRAMES];
|
||||
float foff_coarse_log[FRAMES];
|
||||
float foff_log[FRAMES];
|
||||
COMP rx_fdm_filter_log[(M_FAC+M_FAC/P)*FRAMES];
|
||||
int rx_fdm_filter_log_index;
|
||||
COMP rx_filt_log[NC+1][(P+1)*FRAMES];
|
||||
int rx_filt_log_col_index;
|
||||
float env_log[NT*P*FRAMES];
|
||||
float rx_timing_log[FRAMES];
|
||||
COMP rx_symbols_log[FDMDV_NC+1][FRAMES];
|
||||
COMP phase_difference_log[FDMDV_NC+1][FRAMES];
|
||||
float sig_est_log[FDMDV_NC+1][FRAMES];
|
||||
float noise_est_log[FDMDV_NC+1][FRAMES];
|
||||
int rx_bits_log[FDMDV_BITS_PER_FRAME*FRAMES];
|
||||
float foff_fine_log[FRAMES];
|
||||
int sync_bit_log[FRAMES];
|
||||
int sync_log[FRAMES];
|
||||
int nin_log[FRAMES];
|
||||
|
||||
int f,c,i,j,r;
|
||||
|
||||
|
||||
rx_fdm_filter_log_index = 0;
|
||||
rx_filt_log_col_index = 0;
|
||||
|
||||
printf("sizeof FDMDV states: %zd bytes\n", sizeof(struct FDMDV));
|
||||
|
||||
|
||||
for(r=0; r<numberOfRuns; r++) {
|
||||
f = (currentRun*numberOfRuns+r)%FRAMES;
|
||||
|
||||
/* --------------------------------------------------------*\
|
||||
Modulator
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
fdmdv_get_test_bits(fdmdv, tx_bits);
|
||||
bits_to_dqpsk_symbols(tx_symbols, FDMDV_NC, fdmdv->prev_tx_symbols, tx_bits, &fdmdv->tx_pilot_bit, 0);
|
||||
memcpy(fdmdv->prev_tx_symbols, tx_symbols, sizeof(COMP)*(FDMDV_NC+1));
|
||||
tx_filter_and_upconvert(tx_fdm, FDMDV_NC , tx_symbols, fdmdv->tx_filter_memory,
|
||||
fdmdv->phase_tx, fdmdv->freq, &fdmdv->fbb_phase_tx, fdmdv->fbb_rect);
|
||||
|
||||
/* --------------------------------------------------------*\
|
||||
Channel
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
nin = next_nin;
|
||||
|
||||
// nin = M_FAC; // when debugging good idea to uncomment this to "open loop"
|
||||
|
||||
/* add M_FAC tx samples to end of buffer */
|
||||
|
||||
assert((channel_count + M_FAC) < CHANNEL_BUF_SIZE);
|
||||
for(i=0; i<M_FAC; i++)
|
||||
channel[channel_count+i] = tx_fdm[i].real;
|
||||
channel_count += M_FAC;
|
||||
|
||||
/* take nin samples from start of buffer */
|
||||
|
||||
for(i=0; i<nin; i++) {
|
||||
rx_fdm[i].real = channel[i];
|
||||
rx_fdm[i].imag = 0;
|
||||
}
|
||||
|
||||
/* shift buffer back */
|
||||
|
||||
for(i=0,j=nin; j<channel_count; i++,j++)
|
||||
channel[i] = channel[j];
|
||||
channel_count -= nin;
|
||||
|
||||
/* --------------------------------------------------------*\
|
||||
Demodulator
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
/* shift down to complex baseband */
|
||||
profileTimedEventStart(ProfileTP9);
|
||||
fdmdv_freq_shift(rx_fdm, rx_fdm, -FDMDV_FCENTRE, &fdmdv->fbb_phase_rx, nin);
|
||||
profileTimedEventStop(ProfileTP9);
|
||||
/* freq offset estimation and correction */
|
||||
|
||||
// fdmdv->sync = 0; // when debugging good idea to uncomment this to "open loop"
|
||||
profileTimedEventStart(ProfileTP1);
|
||||
foff_coarse = rx_est_freq_offset(fdmdv, rx_fdm, nin, !fdmdv->sync);
|
||||
profileTimedEventStop(ProfileTP1);
|
||||
|
||||
if (fdmdv->sync == 0)
|
||||
fdmdv->foff = foff_coarse;
|
||||
profileTimedEventStart(ProfileTP2);
|
||||
fdmdv_freq_shift(rx_fdm_fcorr, rx_fdm, -fdmdv->foff, &fdmdv->foff_phase_rect, nin);
|
||||
profileTimedEventStop(ProfileTP2);
|
||||
/* baseband processing */
|
||||
|
||||
rxdec_filter(rx_fdm_filter, rx_fdm_fcorr, fdmdv->rxdec_lpf_mem, nin);
|
||||
|
||||
profileTimedEventStart(ProfileTP3);
|
||||
down_convert_and_rx_filter(rx_filt, fdmdv->Nc, rx_fdm_filter, fdmdv->rx_fdm_mem, fdmdv->phase_rx, fdmdv->freq,
|
||||
fdmdv->freq_pol, nin, M_FAC/Q);
|
||||
profileTimedEventStop(ProfileTP3);
|
||||
profileTimedEventStart(ProfileTP4);
|
||||
rx_timing = rx_est_timing(rx_symbols, FDMDV_NC, rx_filt, fdmdv->rx_filter_mem_timing, env, nin, M_FAC);
|
||||
profileTimedEventStop(ProfileTP4);
|
||||
profileTimedEventStart(ProfileTP5);
|
||||
foff_fine = qpsk_to_bits(rx_bits, &sync_bit, FDMDV_NC, fdmdv->phase_difference, fdmdv->prev_rx_symbols, rx_symbols, 0);
|
||||
profileTimedEventStop(ProfileTP5);
|
||||
|
||||
//for(i=0; i<FDMDV_NC;i++)
|
||||
// printf("rx_symbols: %f %f prev_rx_symbols: %f %f phase_difference: %f %f\n", rx_symbols[i].real, rx_symbols[i].imag,
|
||||
// fdmdv->prev_rx_symbols[i].real, fdmdv->prev_rx_symbols[i].imag, fdmdv->phase_difference[i].real, fdmdv->phase_difference[i].imag);
|
||||
//if (f==1)
|
||||
// exit(0);
|
||||
profileTimedEventStart(ProfileTP6);
|
||||
snr_update(fdmdv->sig_est, fdmdv->noise_est, FDMDV_NC, fdmdv->phase_difference);
|
||||
profileTimedEventStop(ProfileTP6);
|
||||
memcpy(fdmdv->prev_rx_symbols, rx_symbols, sizeof(COMP)*(FDMDV_NC+1));
|
||||
|
||||
next_nin = M_FAC;
|
||||
|
||||
if (rx_timing > 2*M_FAC/P)
|
||||
next_nin += M_FAC/P;
|
||||
|
||||
if (rx_timing < 0)
|
||||
next_nin -= M_FAC/P;
|
||||
profileTimedEventStart(ProfileTP7);
|
||||
fdmdv->sync = freq_state(&reliable_sync_bit, sync_bit, &fdmdv->fest_state, &fdmdv->timer, fdmdv->sync_mem);
|
||||
profileTimedEventStop(ProfileTP7);
|
||||
fdmdv->foff -= TRACK_COEFF*foff_fine;
|
||||
|
||||
/* --------------------------------------------------------*\
|
||||
Log each vector
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
memcpy(&tx_bits_log[FDMDV_BITS_PER_FRAME*f], tx_bits, sizeof(int)*FDMDV_BITS_PER_FRAME);
|
||||
memcpy(&tx_symbols_log[(FDMDV_NC+1)*f], tx_symbols, sizeof(COMP)*(FDMDV_NC+1));
|
||||
memcpy(&tx_fdm_log[M_FAC*f], tx_fdm, sizeof(COMP)*M_FAC);
|
||||
|
||||
memcpy(&pilot_baseband1_log[f*NPILOTBASEBAND], fdmdv->pilot_baseband1, sizeof(COMP)*NPILOTBASEBAND);
|
||||
memcpy(&pilot_baseband2_log[f*NPILOTBASEBAND], fdmdv->pilot_baseband2, sizeof(COMP)*NPILOTBASEBAND);
|
||||
memcpy(&pilot_lpf1_log[f*NPILOTLPF], fdmdv->pilot_lpf1, sizeof(COMP)*NPILOTLPF);
|
||||
memcpy(&pilot_lpf2_log[f*NPILOTLPF], fdmdv->pilot_lpf2, sizeof(COMP)*NPILOTLPF);
|
||||
memcpy(&S1_log[f*MPILOTFFT], fdmdv->S1, sizeof(COMP)*MPILOTFFT);
|
||||
memcpy(&S2_log[f*MPILOTFFT], fdmdv->S2, sizeof(COMP)*MPILOTFFT);
|
||||
foff_coarse_log[f] = foff_coarse;
|
||||
foff_log[f] = fdmdv->foff;
|
||||
|
||||
/* rx filtering */
|
||||
|
||||
for(i=0; i<nin; i++)
|
||||
rx_fdm_filter_log[rx_fdm_filter_log_index + i] = rx_fdm_filter[i];
|
||||
rx_fdm_filter_log_index += nin;
|
||||
|
||||
for(c=0; c<NC+1; c++) {
|
||||
for(i=0; i<(P*nin)/M_FAC; i++)
|
||||
rx_filt_log[c][rx_filt_log_col_index + i] = rx_filt[c][i];
|
||||
}
|
||||
rx_filt_log_col_index += (P*nin)/M_FAC;
|
||||
|
||||
/* timing estimation */
|
||||
|
||||
memcpy(&env_log[NT*P*f], env, sizeof(float)*NT*P);
|
||||
rx_timing_log[f] = rx_timing;
|
||||
nin_log[f] = nin;
|
||||
|
||||
for(c=0; c<FDMDV_NC+1; c++) {
|
||||
rx_symbols_log[c][f] = rx_symbols[c];
|
||||
phase_difference_log[c][f] = fdmdv->phase_difference[c];
|
||||
}
|
||||
|
||||
/* qpsk_to_bits() */
|
||||
|
||||
memcpy(&rx_bits_log[FDMDV_BITS_PER_FRAME*f], rx_bits, sizeof(int)*FDMDV_BITS_PER_FRAME);
|
||||
for(c=0; c<FDMDV_NC+1; c++) {
|
||||
sig_est_log[c][f] = fdmdv->sig_est[c];
|
||||
noise_est_log[c][f] = fdmdv->noise_est[c];
|
||||
}
|
||||
foff_fine_log[f] = foff_fine;
|
||||
sync_bit_log[f] = sync_bit;
|
||||
|
||||
sync_log[f] = fdmdv->sync;
|
||||
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
Dump logs to Octave file for evaluation
|
||||
by tfdmdv.m Octave script
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
if (cumulativeOutput == 0 || (currentRun*FRAMES+f) == (FRAMES*FRAMERUNS - 1))
|
||||
{
|
||||
int range=cumulativeOutput?FRAMES:1;
|
||||
int start=cumulativeOutput?0:f;
|
||||
|
||||
|
||||
#if CUMULATIVE
|
||||
profileEventsTracePrint();
|
||||
#endif
|
||||
octave_save_int(fout, "tx_bits_log_c", &tx_bits_log[start * FDMDV_BITS_PER_FRAME], 1, FDMDV_BITS_PER_FRAME*range);
|
||||
octave_save_complex(fout, "tx_symbols_log_c", &tx_symbols_log[(FDMDV_NC+1)*start], 1, (FDMDV_NC+1)*range, (FDMDV_NC+1)*FRAMES);
|
||||
octave_save_complex(fout, "tx_fdm_log_c", &tx_fdm_log[M_FAC*start], 1, M_FAC*range, M_FAC*FRAMES);
|
||||
octave_save_complex(fout, "pilot_lut_c", fdmdv->pilot_lut, 1, NPILOT_LUT, NPILOT_LUT);
|
||||
octave_save_complex(fout, "pilot_baseband1_log_c", &pilot_baseband1_log[start*NPILOTBASEBAND], 1, NPILOTBASEBAND*range, NPILOTBASEBAND*FRAMES);
|
||||
octave_save_complex(fout, "pilot_baseband2_log_c", &pilot_baseband2_log[start*NPILOTBASEBAND], 1, NPILOTBASEBAND*range, NPILOTBASEBAND*FRAMES);
|
||||
octave_save_float(fout, "pilot_coeff_c", pilot_coeff, 1, NPILOTCOEFF, NPILOTCOEFF);
|
||||
octave_save_complex(fout, "pilot_lpf1_log_c", &pilot_lpf1_log[NPILOTLPF*start], 1, NPILOTLPF*range, NPILOTLPF*FRAMES);
|
||||
octave_save_complex(fout, "pilot_lpf2_log_c", &pilot_lpf2_log[NPILOTLPF*start], 1, NPILOTLPF*range, NPILOTLPF*FRAMES);
|
||||
octave_save_complex(fout, "S1_log_c", &S1_log[MPILOTFFT*start], 1, MPILOTFFT*range, MPILOTFFT*FRAMES);
|
||||
octave_save_complex(fout, "S2_log_c", &S2_log[MPILOTFFT*start], 1, MPILOTFFT*range, MPILOTFFT*FRAMES);
|
||||
octave_save_float(fout, "foff_log_c", &foff_log[start], 1, range, FRAMES);
|
||||
octave_save_float(fout, "foff_coarse_log_c", &foff_coarse_log[start], 1, range, FRAMES);
|
||||
octave_save_complex(fout, "rx_fdm_filter_log_c", &rx_fdm_filter_log[cumulativeOutput?0:rx_fdm_filter_log_index-nin_log[start]], 1, cumulativeOutput?rx_fdm_filter_log_index:nin_log[start], cumulativeOutput?rx_fdm_filter_log_index:nin_log[start]);
|
||||
|
||||
int rx_f_l_diff = cumulativeOutput?rx_filt_log_col_index:(P*nin_log[start])/M_FAC;
|
||||
int rx_f_l_start = rx_filt_log_col_index - rx_f_l_diff;
|
||||
|
||||
octave_save_complex(fout, "rx_filt_log_c", &rx_filt_log[0][rx_f_l_start], (FDMDV_NC+1), rx_f_l_diff, (P+1)*FRAMES);
|
||||
octave_save_float(fout, "env_log_c", &env_log[start*NT*P], 1, NT*P*range, NT*P*FRAMES);
|
||||
octave_save_float(fout, "rx_timing_log_c", &rx_timing_log[start], 1, range, FRAMES);
|
||||
octave_save_complex(fout, "rx_symbols_log_c", &rx_symbols_log[0][start], (FDMDV_NC+1), range, FRAMES);
|
||||
octave_save_complex(fout, "phase_difference_log_c", &phase_difference_log[0][start], (FDMDV_NC+1), range, FRAMES);
|
||||
octave_save_float(fout, "sig_est_log_c", &sig_est_log[0][start], (FDMDV_NC+1), range, FRAMES);
|
||||
octave_save_float(fout, "noise_est_log_c", &noise_est_log[0][start], (FDMDV_NC+1), range, FRAMES);
|
||||
octave_save_int(fout, "rx_bits_log_c", &rx_bits_log[FDMDV_BITS_PER_FRAME*start], 1, FDMDV_BITS_PER_FRAME*range);
|
||||
octave_save_float(fout, "foff_fine_log_c", &foff_fine_log[start], 1, range , FRAMES);
|
||||
octave_save_int(fout, "sync_bit_log_c", &sync_bit_log[start], 1, range);
|
||||
octave_save_int(fout, "sync_log_c", &sync_log[start], 1, range);
|
||||
octave_save_int(fout, "nin_log_c", &nin_log[start], 1, range);
|
||||
}
|
||||
}
|
||||
|
||||
return next_nin;
|
||||
}
|
||||
|
||||
int tfdmdv_main(int argc, char* argv[])
|
||||
{
|
||||
#ifndef ARM_MATH_CM4
|
||||
fout = fopen("tfdmdv_out.txt","wt");
|
||||
assert(fout != NULL);
|
||||
#endif
|
||||
#ifdef PROFILE_EVENTS
|
||||
profileTimedEventInit();
|
||||
#endif
|
||||
FPRINTF(fout, "# Created by tfdmdv.c\n");
|
||||
fdmdv = fdmdv_create(FDMDV_NC);
|
||||
|
||||
int i = 0;
|
||||
int next_nin = M_FAC;
|
||||
channel_count = 0;
|
||||
for (i = 0; i < FRAMERUNS; i++)
|
||||
{
|
||||
next_nin = run(CUMULATIVE,FRAMEINCR,i,next_nin);
|
||||
}
|
||||
#ifndef ARM_MATH_CM4
|
||||
fclose(fout);
|
||||
#endif
|
||||
|
||||
fdmdv_destroy(fdmdv);
|
||||
return 0;
|
||||
}
|
||||
#ifndef ARM_MATH_CM4
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
tfdmdv_main(argc,argv)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR **
|
||||
** a powerful firmware for STM32 based SDR transceivers **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "uhsdr_canary.h"
|
||||
|
||||
static const uint8_t canary_word[] = { 'D', 'O', ' ', 'G', 'N', 'U', ' ', 'G', 'P', 'L', 'v', '3' };
|
||||
uint8_t* canary_word_ptr;
|
||||
|
||||
/**
|
||||
* this has to be called after all dynamic memory allocation has happened
|
||||
*/
|
||||
void Canary_Create( void )
|
||||
{
|
||||
canary_word_ptr = (uint8_t*)malloc( sizeof( canary_word ));
|
||||
assert( canary_word_ptr );
|
||||
memcpy ( canary_word_ptr, canary_word, sizeof(canary_word) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the canary was not destroyed (i.e. no additional allocation has happened and/or some code went wild.
|
||||
*
|
||||
* this has to be called after all dynamic memory allocation has happened AND Canary_Create has been called
|
||||
*
|
||||
* @return true if the previously written canary is still found in its location
|
||||
*/
|
||||
bool Canary_IsIntact( void )
|
||||
{
|
||||
return memcmp ( canary_word_ptr, canary_word, sizeof(canary_word) ) == 0;
|
||||
}
|
||||
|
||||
uint8_t* Canary_GetAddr( void )
|
||||
{
|
||||
return canary_word_ptr;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR **
|
||||
** a powerful firmware for STM32 based SDR transceivers **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
#ifndef __UHSDR_CANARY_H
|
||||
#define __UHSDR_CANARY_H
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
|
||||
void Canary_Create ( void );
|
||||
bool Canary_IsIntact ( void );
|
||||
uint8_t* Canary_GetAddr ( void );
|
||||
|
||||
#endif // __UHSDR_CANARY_H
|
||||
@@ -0,0 +1,66 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR **
|
||||
** a powerful firmware for STM32 based SDR transceivers **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "uhsdr_math.h"
|
||||
|
||||
/**
|
||||
* Fast algorithm for log10
|
||||
*
|
||||
* This is a fast approximation to log2()
|
||||
* Y = C[0]*F*F*F + C[1]*F*F + C[2]*F + C[3] + E;
|
||||
* log10f is exactly log2(x)/log2(10.0f)
|
||||
* Math_log10f_fast(x) =(log2f_approx(x)*0.3010299956639812f)
|
||||
*
|
||||
* @param X number want log10 for
|
||||
* @return log10(x)
|
||||
*/
|
||||
float32_t Math_log10f_fast(float32_t X) {
|
||||
float Y, F;
|
||||
int E;
|
||||
F = frexpf(fabsf(X), &E);
|
||||
Y = 1.23149591368684f;
|
||||
Y *= F;
|
||||
Y += -4.11852516267426f;
|
||||
Y *= F;
|
||||
Y += 6.02197014179219f;
|
||||
Y *= F;
|
||||
Y += -3.13396450166353f;
|
||||
Y += E;
|
||||
return(Y * 0.3010299956639812f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the absolute (i.e. ignoring the sign) maximum value
|
||||
* @param float32_t buffer to be searched
|
||||
* @param size how many elements
|
||||
* @return the actual maxium value of the size elements in buffer
|
||||
*/
|
||||
float32_t Math_absmax(float32_t* buffer, int size)
|
||||
{
|
||||
float32_t min, max;
|
||||
uint32_t pindex;
|
||||
|
||||
arm_max_f32(buffer, size, &max, &pindex); // find absolute value of audio in buffer after gain applied
|
||||
arm_min_f32(buffer, size, &min, &pindex);
|
||||
|
||||
return -min>max?-min:max;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the sign of a float number
|
||||
* @param x the number to test
|
||||
* @return -1 if below zero, 0 if zero, 1 if above zero
|
||||
*/
|
||||
float32_t Math_sign_new (float32_t x) {
|
||||
return (x < 0) ? -1.0 : ( (x > 0) ? 1.0 : 0.0);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/************************************************************************************
|
||||
** **
|
||||
** UHSDR **
|
||||
** a powerful firmware for STM32 based SDR transceivers **
|
||||
** **
|
||||
**---------------------------------------------------------------------------------**
|
||||
** **
|
||||
** Licence: GNU GPLv3 **
|
||||
************************************************************************************/
|
||||
#ifndef __UHSDR_MATH_H
|
||||
#define __UHSDR_MATH_H
|
||||
|
||||
#include "uhsdr_types.h"
|
||||
float32_t Math_log10f_fast(float32_t X);
|
||||
float32_t Math_absmax(float32_t* buffer, int size);
|
||||
float32_t Math_sign_new (float32_t x);
|
||||
|
||||
#endif // __UHSDR_MATH_H
|
||||
@@ -0,0 +1,699 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file EEPROM_Emulation/src/eeprom.c
|
||||
* @author MCD Application Team
|
||||
* @version V1.0.0
|
||||
* @date 10-October-2011
|
||||
* @brief This file provides all the EEPROM emulation firmware functions.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/** @addtogroup EEPROM_Emulation
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "uhsdr_mcu.h"
|
||||
#include "config_storage.h"
|
||||
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
|
||||
be done by word */
|
||||
#define VOLTAGE_RANGE VOLTAGE_RANGE_3
|
||||
|
||||
/* Pages 0 and 1 base and end addresses */
|
||||
#define PAGE0_BASE_ADDRESS ((uint32_t)(EEPROM_START_ADDRESS + 0x0000))
|
||||
#define PAGE0_END_ADDRESS ((uint32_t)(EEPROM_START_ADDRESS + (PAGE_SIZE - 1)))
|
||||
|
||||
#define PAGE1_BASE_ADDRESS ((uint32_t)(EEPROM_START_ADDRESS + PAGE_SIZE))
|
||||
#define PAGE1_END_ADDRESS ((uint32_t)(EEPROM_START_ADDRESS + (2 * PAGE_SIZE - 1)))
|
||||
|
||||
/* Used Flash pages for EEPROM emulation */
|
||||
#define PAGE0 ((uint16_t)0x0000)
|
||||
#define PAGE1 ((uint16_t)0x0001)
|
||||
|
||||
/* No valid page define */
|
||||
#define NO_VALID_PAGE ((uint16_t)0x00AB)
|
||||
|
||||
/* Page status definitions */
|
||||
#define ERASED ((uint16_t)0xFFFF) /* Page is empty */
|
||||
#define RECEIVE_DATA ((uint16_t)0xEEEE) /* Page is marked to receive data */
|
||||
#define VALID_PAGE ((uint16_t)0x0000) /* Page containing valid data */
|
||||
|
||||
/* Valid pages in read and write defines */
|
||||
#define READ_FROM_VALID_PAGE ((uint8_t)0x00)
|
||||
#define RECEIVE_WRITE_PAGE ((uint8_t)0x01)
|
||||
#define WRITE_TO_VALID_PAGE ((uint8_t)0x02)
|
||||
|
||||
|
||||
/* Page full define */
|
||||
#define PAGE_FULL ((uint8_t)0x80)
|
||||
|
||||
|
||||
// Common
|
||||
#ifndef USE_HAL_DRIVER
|
||||
#define USE_HAL_DRIVER
|
||||
#endif
|
||||
#include "uhsdr_board.h"
|
||||
#ifdef STM32F7
|
||||
#include "stm32f7xx_hal_flash_ex.h"
|
||||
#elif defined(STM32H7)
|
||||
#include "stm32h7xx_hal_flash_ex.h"
|
||||
#elif defined(STM32F4)
|
||||
#include "stm32f4xx_hal_flash_ex.h"
|
||||
#endif
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "uhsdr_flash.h"
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
#define VAR_ADDR_START (0xAA01)
|
||||
// this value is required to remain unchanged in order to not break existing mcHF flash configuration
|
||||
// readings. It is otherwise just an arbitrary number.
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
/* Global variable used to store variable value in read sequence */
|
||||
static uint16_t DataVar = 0;
|
||||
|
||||
/* Virtual address defined by the user: 0xFFFF value is prohibited */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
static HAL_StatusTypeDef Flash_Format(void);
|
||||
static uint16_t Flash_FindPage(uint8_t Operation);
|
||||
static uint16_t Flash_WriteVariableToPage(uint16_t VirtAddress, uint16_t Data, uint8_t pageType);
|
||||
static uint16_t Flash_PageTransfer(uint16_t VirtAddress);
|
||||
|
||||
|
||||
HAL_StatusTypeDef Flash_Erase(uint32_t sector)
|
||||
{
|
||||
FLASH_EraseInitTypeDef flashEraseOp;
|
||||
uint32_t sectorError = 0;
|
||||
|
||||
flashEraseOp.Sector = sector;
|
||||
flashEraseOp.NbSectors = 1;
|
||||
flashEraseOp.VoltageRange = VOLTAGE_RANGE;
|
||||
flashEraseOp.TypeErase = FLASH_TYPEERASE_SECTORS;
|
||||
|
||||
#if defined(STM32H7)
|
||||
flashEraseOp.Banks = FLASH_BANK_1;
|
||||
#endif
|
||||
|
||||
return HAL_FLASHEx_Erase(&flashEraseOp, §orError);
|
||||
|
||||
}
|
||||
/**
|
||||
* This code encapsulates the former direct use of mapping table
|
||||
* Since we never used the mapping table except for mapping to an offset,
|
||||
* we now use code to convert the id (start from 0) to addresses (starting from VAR_ADDR_START)
|
||||
* This allows full backward compatibility of stored settings.
|
||||
*/
|
||||
uint16_t Flash_GetVirtAddrForId(uint16_t id) {
|
||||
return VAR_ADDR_START + id;
|
||||
}
|
||||
|
||||
static HAL_StatusTypeDef Flash_Program(uint32_t toAddress,uint16_t value, uint16_t virtaddr)
|
||||
{
|
||||
HAL_StatusTypeDef retval = HAL_ERROR;
|
||||
uint32_t word = (((uint32_t)virtaddr) << 16)| value;
|
||||
// combine both parameters into a single 32bit word
|
||||
#if defined(STM32F4) || defined(STM32F7)
|
||||
retval = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,toAddress, word);
|
||||
#elif defined(STM32H7)
|
||||
// this code is used to simulate 32bit wide writing on a 256bit flash word
|
||||
// this adds 8 times the amount of writing to a 256 bit location but what can we
|
||||
// do, either this or we waste up to 78.5% of the config flash
|
||||
uint32_t data[8];
|
||||
uint32_t* startaddr = (uint32_t*)(toAddress & ~0xFFFFFFE0);
|
||||
// mask out the lower 5 bits, we have to read 8x4 = 32 bytes aligned to a 32byte address;
|
||||
uint32_t wordidx = (toAddress % 32) / 4; // now figure out where our data goes
|
||||
for (int idx = 0; idx < 8; idx++)
|
||||
{
|
||||
if (idx != wordidx)
|
||||
{
|
||||
data[idx] = startaddr[idx];
|
||||
}
|
||||
else
|
||||
{
|
||||
data[idx] = word;
|
||||
}
|
||||
|
||||
}
|
||||
retval = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD,toAddress, (uint32_t)&data[0]);
|
||||
#else
|
||||
#error "No support for unknown processor implemented"
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static bool Flash_PageIsErased(uint8_t page)
|
||||
{
|
||||
bool retval = true;
|
||||
uint32_t* pagePtr = (uint32_t*)(page==PAGE0?PAGE0_BASE_ADDRESS:PAGE1_BASE_ADDRESS);
|
||||
for (uint16_t idx = 0; idx < PAGE_SIZE/sizeof(uint32_t);idx++)
|
||||
{
|
||||
if (pagePtr[idx] != 0xFFFFFFFF)
|
||||
{
|
||||
retval =false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
HAL_StatusTypeDef Flash_Check_And_EraseIfNeeded(uint8_t page)
|
||||
{
|
||||
HAL_StatusTypeDef retval = HAL_OK;
|
||||
if (Flash_PageIsErased(page) == false)
|
||||
{
|
||||
retval =Flash_Erase(page == PAGE0? PAGE0_ID : PAGE1_ID);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static uint16_t Flash_TransferFullPage(uint8_t fromPage, uint8_t toPage, bool skip, uint16_t skipAddress)
|
||||
{
|
||||
uint32_t toPageBaseAddress = toPage==PAGE0?PAGE0_BASE_ADDRESS:PAGE1_BASE_ADDRESS;
|
||||
// uint32_t fromPageBaseAddress = fromPage==PAGE0?PAGE0_BASE_ADDRESS:PAGE1_BASE_ADDRESS;
|
||||
|
||||
uint16_t retval = HAL_OK;
|
||||
|
||||
/* Transfer data from Page0 to Page1 */
|
||||
for (uint16_t VarIdx = 0; retval == HAL_OK && VarIdx < NB_OF_VAR; VarIdx++)
|
||||
{
|
||||
uint16_t virtAddress = Flash_GetVirtAddrForId(VarIdx);
|
||||
|
||||
if ((*(__IO uint16_t*)(toPageBaseAddress + 6)) != virtAddress && (!skip || virtAddress != skipAddress))
|
||||
{
|
||||
/* Read the last variables' updates */
|
||||
uint16_t ReadStatus = Flash_ReadVariable(virtAddress, &DataVar);
|
||||
/* In case variable corresponding to the virtual address was found */
|
||||
if (ReadStatus != 0x1)
|
||||
{
|
||||
/* Transfer the variable to the Page1 */
|
||||
retval = Flash_WriteVariableToPage(virtAddress, DataVar, RECEIVE_WRITE_PAGE);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (retval != HAL_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Mark toPage as valid */
|
||||
retval = Flash_Program(toPageBaseAddress, VALID_PAGE, 0xFFFF);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (retval == HAL_OK)
|
||||
{
|
||||
/* Erase Page0 */
|
||||
retval = Flash_Erase(fromPage);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Restore the pages to a known good state in case of page's status
|
||||
* corruption after a power loss.
|
||||
* @param None.
|
||||
* @retval - Flash error code: on write Flash error
|
||||
* - HAL_OK: on success
|
||||
*/
|
||||
uint16_t Flash_InitA(void)
|
||||
{
|
||||
|
||||
/* 1
|
||||
* 0: V E R ?
|
||||
* V EB C0 T0 E0
|
||||
* E C1 V0 E0 E0
|
||||
* R T1 EB EB EB
|
||||
* ? E1 E1 EB EB
|
||||
*
|
||||
* Cx: Check Erase x
|
||||
* Ex: Erase x 0,1,Both
|
||||
* Tx: Transfer to x
|
||||
* V0: Make Page 0 valid page
|
||||
*/
|
||||
uint16_t PageStatus0, PageStatus1;
|
||||
uint16_t retval = 0x80;
|
||||
|
||||
|
||||
// FIXME: F7PORT: How to get rid of this? After change, boards needs reflash
|
||||
// if the process can do dual bank mode,
|
||||
// switch this ON, otherwise we have already the correct
|
||||
// sector layout
|
||||
#if defined (FLASH_OPTCR_nDBANK)
|
||||
HAL_FLASH_OB_Unlock();
|
||||
FLASH->OPTCR &= ~FLASH_OPTCR_nDBANK;
|
||||
HAL_FLASH_OB_Launch();
|
||||
HAL_FLASH_OB_Lock();
|
||||
#endif
|
||||
|
||||
|
||||
/* Get Page0 status */
|
||||
PageStatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);
|
||||
/* Get Page1 status */
|
||||
PageStatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);
|
||||
|
||||
/* Check for invalid header states and repair if necessary */
|
||||
switch (PageStatus0)
|
||||
{
|
||||
case ERASED:
|
||||
if (PageStatus1 == VALID_PAGE) /* Page0 erased, Page1 valid */
|
||||
{
|
||||
/* Erase Page0 */
|
||||
retval = Flash_Check_And_EraseIfNeeded(PAGE0);
|
||||
}
|
||||
else if (PageStatus1 == RECEIVE_DATA) /* Page0 erased, Page1 receive */
|
||||
{
|
||||
/* Erase Page0 */
|
||||
retval = Flash_Check_And_EraseIfNeeded(PAGE0);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (retval == HAL_OK)
|
||||
{
|
||||
/* Mark Page1 as valid */
|
||||
retval = Flash_Program(PAGE1_BASE_ADDRESS, VALID_PAGE, 0xFFFF);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RECEIVE_DATA:
|
||||
if (PageStatus1 == VALID_PAGE) /* Page0 receive, Page1 valid */
|
||||
{
|
||||
retval = Flash_TransferFullPage(PAGE1_ID, PAGE0_ID, false, 0);
|
||||
/* Transfer data from Page1 to Page0 */
|
||||
}
|
||||
else if (PageStatus1 == ERASED) /* Page0 receive, Page1 erased */
|
||||
{
|
||||
/* Erase Page1 */
|
||||
retval = Flash_Check_And_EraseIfNeeded(PAGE0);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (retval == HAL_OK)
|
||||
{
|
||||
/* Mark Page0 as valid */
|
||||
retval = Flash_Program(PAGE0_BASE_ADDRESS, VALID_PAGE, 0xFFFF);
|
||||
}
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
}
|
||||
break;
|
||||
|
||||
case VALID_PAGE:
|
||||
if (PageStatus1 == VALID_PAGE) /* Invalid state -> format eeprom */
|
||||
{
|
||||
/* Erase both Page0 and Page1 and set Page0 as valid page */
|
||||
retval = Flash_Format();
|
||||
}
|
||||
else if (PageStatus1 == ERASED) /* Page0 valid, Page1 erased */
|
||||
{
|
||||
/* Erase Page1 */
|
||||
retval = Flash_Check_And_EraseIfNeeded(PAGE1);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
}
|
||||
else if (PageStatus1 == RECEIVE_DATA)/* Page0 valid, Page1 receive */
|
||||
{
|
||||
retval = Flash_TransferFullPage(PAGE0_ID, PAGE1_ID, false, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid state on page1 -> format eeprom page 1 */
|
||||
retval = Flash_Check_And_EraseIfNeeded(PAGE1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (PageStatus1 == VALID_PAGE) /* Invalid state on page0 -> format eeprom page 0 */
|
||||
{
|
||||
/* Erase Page0 */
|
||||
retval = Flash_Check_And_EraseIfNeeded(PAGE0);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == 0x80)
|
||||
{
|
||||
/* In case of real trouble we try to recover by erasing the whole flash memory */
|
||||
retval = Flash_Format();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Proxy
|
||||
uint16_t Flash_Init(void)
|
||||
{
|
||||
uint16_t res;
|
||||
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
res = Flash_InitA();
|
||||
HAL_FLASH_Lock();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last stored variable data, if found, which correspond to
|
||||
* the passed virtual address
|
||||
* @param VirtAddress: Variable virtual address
|
||||
* @param Data: Global variable contains the read variable value
|
||||
* @retval Success or error status:
|
||||
* - 0: if variable was found
|
||||
* - 1: if the variable was not found
|
||||
* - NO_VALID_PAGE: if no valid page was found.
|
||||
*/
|
||||
uint16_t Flash_ReadVariable(uint16_t addr, uint16_t* value)
|
||||
{
|
||||
uint16_t VirtAddress = Flash_GetVirtAddrForId(addr);
|
||||
uint16_t ValidPage;
|
||||
uint16_t AddressValue = 0x5555, ReadStatus = 1;
|
||||
uint32_t Address = EEPROM_START_ADDRESS, PageStartAddress = EEPROM_START_ADDRESS;
|
||||
|
||||
/* Get active Page for read operation */
|
||||
ValidPage = Flash_FindPage(READ_FROM_VALID_PAGE);
|
||||
|
||||
/* Check if there is no valid page */
|
||||
if (ValidPage == NO_VALID_PAGE)
|
||||
{
|
||||
return NO_VALID_PAGE;
|
||||
}
|
||||
|
||||
/* Get the valid Page start Address */
|
||||
PageStartAddress = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(ValidPage * PAGE_SIZE));
|
||||
|
||||
/* Get the valid Page end Address */
|
||||
Address = (uint32_t)((EEPROM_START_ADDRESS - 2) + (uint32_t)((1 + ValidPage) * PAGE_SIZE));
|
||||
|
||||
/* Check each active page address starting from end */
|
||||
while (Address > (PageStartAddress + 2))
|
||||
{
|
||||
/* Get the current location content to be compared with virtual address */
|
||||
AddressValue = (*(__IO uint16_t*)Address);
|
||||
|
||||
/* Compare the read address with the virtual address */
|
||||
if (AddressValue == VirtAddress)
|
||||
{
|
||||
/* Get content of Address-2 which is variable value */
|
||||
*value = (*(__IO uint16_t*)(Address - 2));
|
||||
|
||||
/* In case variable value is read, reset ReadStatus flag */
|
||||
ReadStatus = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Next address location */
|
||||
Address = Address - 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return ReadStatus value: (0: variable exist, 1: variable doesn't exist) */
|
||||
return ReadStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes/updates variable data in EEPROM if necessary.
|
||||
* @param VirtAddress: Variable virtual address
|
||||
* @param Data: 16 bit data to be written
|
||||
* @retval Success or error status:
|
||||
* - HAL_OK: on success
|
||||
* - PAGE_FULL: if valid page is full
|
||||
* - NO_VALID_PAGE: if no valid page was found
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
uint16_t Flash_UpdateVariable(uint16_t addr, uint16_t value)
|
||||
{
|
||||
uint16_t DataRead = 0;
|
||||
uint16_t Status = 0;
|
||||
Status = Flash_ReadVariable(addr,&DataRead);
|
||||
// the variable was found and the data content is equal to the new value
|
||||
// -> no need to write it again
|
||||
if (Status == 0 && DataRead == value)
|
||||
{
|
||||
Status = HAL_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
Status = Flash_WriteVariable(addr, value);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes/updates variable data in EEPROM.
|
||||
* @param VirtAddress: Variable virtual address
|
||||
* @param Data: 16 bit data to be written
|
||||
* @retval Success or error status:
|
||||
* - HAL_OK: on success
|
||||
* - PAGE_FULL: if valid page is full
|
||||
* - NO_VALID_PAGE: if no valid page was found
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
uint16_t Flash_WriteVariable(uint16_t addr, uint16_t value)
|
||||
{
|
||||
uint16_t retval = 0;
|
||||
uint16_t VirtAddress = Flash_GetVirtAddrForId(addr);
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
/* Write the variable virtual address and value in the EEPROM */
|
||||
retval = Flash_WriteVariableToPage(VirtAddress, value,WRITE_TO_VALID_PAGE);
|
||||
|
||||
/* In case the EEPROM active page is full */
|
||||
if (retval == PAGE_FULL)
|
||||
{
|
||||
/* Perform Page transfer and retry write*/
|
||||
retval = Flash_PageTransfer(VirtAddress);
|
||||
if (retval == HAL_OK)
|
||||
{
|
||||
retval = Flash_WriteVariableToPage(VirtAddress, value,WRITE_TO_VALID_PAGE);
|
||||
}
|
||||
}
|
||||
|
||||
HAL_FLASH_Lock();
|
||||
|
||||
/* Return last operation status */
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases PAGE and PAGE1 and writes VALID_PAGE header to PAGE
|
||||
* @param None
|
||||
* @retval Status of the last operation (Flash write or erase) done during
|
||||
* EEPROM formating
|
||||
*/
|
||||
static HAL_StatusTypeDef Flash_Format(void)
|
||||
{
|
||||
HAL_StatusTypeDef FlashStatus;
|
||||
|
||||
/* Erase Page0 */
|
||||
FlashStatus = Flash_Erase(PAGE0_ID);
|
||||
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (FlashStatus != HAL_OK)
|
||||
{
|
||||
return FlashStatus;
|
||||
}
|
||||
|
||||
/* Set Page0 as valid page: Write VALID_PAGE at Page0 base address */
|
||||
FlashStatus = Flash_Program(PAGE0_BASE_ADDRESS, VALID_PAGE, 0xFFFF);
|
||||
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (FlashStatus != HAL_OK)
|
||||
{
|
||||
return FlashStatus;
|
||||
}
|
||||
|
||||
/* Erase Page1 */
|
||||
FlashStatus = Flash_Erase(PAGE1_ID);
|
||||
|
||||
/* Return Page1 erase operation status */
|
||||
return FlashStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find valid Page for write or read operation
|
||||
* @param Operation: operation to achieve on the valid page.
|
||||
* This parameter can be one of the following values:
|
||||
* @arg READ_FROM_VALID_PAGE: read operation from valid page
|
||||
* @arg WRITE_IN_VALID_PAGE: write operation from valid page
|
||||
* @retval Valid page number (PAGE or PAGE1) or NO_VALID_PAGE in case
|
||||
* of no valid page was found
|
||||
*/
|
||||
static uint16_t Flash_FindPage(uint8_t Operation)
|
||||
{
|
||||
uint16_t PageStatus0, PageStatus1;
|
||||
|
||||
/* Get Page0 actual status */
|
||||
PageStatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);
|
||||
|
||||
/* Get Page1 actual status */
|
||||
PageStatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);
|
||||
|
||||
uint16_t retval = NO_VALID_PAGE;
|
||||
|
||||
/* Write or read operation */
|
||||
switch (Operation)
|
||||
{
|
||||
case RECEIVE_WRITE_PAGE: /* ---- Write operation ---- */
|
||||
if (PageStatus1 == VALID_PAGE)
|
||||
{
|
||||
/* Page0 receiving data */
|
||||
if (PageStatus0 == RECEIVE_DATA)
|
||||
{
|
||||
retval = PAGE0; /* Page0 valid */
|
||||
}
|
||||
}
|
||||
else if (PageStatus0 == VALID_PAGE)
|
||||
{
|
||||
/* Page1 receiving data */
|
||||
if (PageStatus1 == RECEIVE_DATA)
|
||||
{
|
||||
retval = PAGE1; /* Page1 valid */
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case READ_FROM_VALID_PAGE: /* ---- Read operation ---- */
|
||||
if (PageStatus0 == VALID_PAGE)
|
||||
{
|
||||
retval = PAGE0; /* Page0 valid */
|
||||
}
|
||||
else if (PageStatus1 == VALID_PAGE)
|
||||
{
|
||||
retval = PAGE1; /* Page1 valid */
|
||||
}
|
||||
break;
|
||||
case WRITE_TO_VALID_PAGE: /* ---- Read operation ---- */
|
||||
if (PageStatus0 == VALID_PAGE)
|
||||
{
|
||||
retval = PAGE0; /* Page0 valid */
|
||||
}
|
||||
else if (PageStatus1 == VALID_PAGE)
|
||||
{
|
||||
retval = PAGE1; /* Page1 valid */
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verify if active page is full and Writes variable in EEPROM.
|
||||
* @param VirtAddress: 16 bit virtual address of the variable
|
||||
* @param Data: 16 bit data to be written as variable value
|
||||
* @retval Success or error status:
|
||||
* - HAL_OK: on success
|
||||
* - PAGE_FULL: if valid page is full
|
||||
* - NO_VALID_PAGE: if no valid page was found
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
static uint16_t Flash_WriteVariableToPage(uint16_t VirtAddress, uint16_t Data, uint8_t pageType)
|
||||
{
|
||||
uint16_t retval = PAGE_FULL;
|
||||
|
||||
uint16_t ReceivePage;
|
||||
uint32_t Address = EEPROM_START_ADDRESS, PageEndAddress = EEPROM_START_ADDRESS+PAGE_SIZE;
|
||||
|
||||
/* Get valid Page for write operation */
|
||||
ReceivePage = Flash_FindPage(pageType);
|
||||
|
||||
/* Check if there is no valid page */
|
||||
if (ReceivePage == NO_VALID_PAGE)
|
||||
{
|
||||
retval = NO_VALID_PAGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the valid Page start Address */
|
||||
Address = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(ReceivePage * PAGE_SIZE));
|
||||
|
||||
/* Get the valid Page end Address */
|
||||
PageEndAddress = (uint32_t)((EEPROM_START_ADDRESS - 2) + (uint32_t)((1 + ReceivePage) * PAGE_SIZE));
|
||||
|
||||
/* Check each active page address starting from begining */
|
||||
for (;Address < PageEndAddress;Address += 4)
|
||||
{
|
||||
/* Verify if Address and Address+2 contents are 0xFFFFFFFF */
|
||||
if ((*(__IO uint32_t*)Address) == 0xFFFFFFFF)
|
||||
{
|
||||
/* Set variable data */
|
||||
retval = Flash_Program(Address, Data, VirtAddress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transfers last updated variables data from the full Page to
|
||||
* an empty one.
|
||||
* @param VirtAddress: 16 bit virtual address of the variable
|
||||
* @param Data: 16 bit data to be written as variable value
|
||||
* @retval Success or error status:
|
||||
* - HAL_OK: on success
|
||||
* - PAGE_FULL: if valid page is full
|
||||
* - NO_VALID_PAGE: if no valid page was found
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
static uint16_t Flash_PageTransfer(uint16_t VirtAddress)
|
||||
{
|
||||
uint32_t NewPageAddress;
|
||||
uint16_t ValidPage;
|
||||
uint16_t NewPage;
|
||||
uint16_t retval = HAL_OK;
|
||||
|
||||
/* Get active Page for read operation */
|
||||
ValidPage = Flash_FindPage(READ_FROM_VALID_PAGE);
|
||||
|
||||
if (ValidPage == PAGE1) /* Page1 valid */
|
||||
{
|
||||
/* New page address where variable will be moved to */
|
||||
NewPageAddress = PAGE0_BASE_ADDRESS;
|
||||
NewPage = PAGE0;
|
||||
}
|
||||
else if (ValidPage == PAGE0) /* Page0 valid */
|
||||
{
|
||||
/* New page address where variable will be moved to */
|
||||
NewPageAddress = PAGE1_BASE_ADDRESS;
|
||||
NewPage = PAGE1;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = NO_VALID_PAGE; /* No valid Page */
|
||||
}
|
||||
|
||||
if (retval == HAL_OK )
|
||||
{
|
||||
/* Set the new Page status to RECEIVE_DATA status */
|
||||
retval = Flash_Program(NewPageAddress, RECEIVE_DATA, 0xFFFF);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (retval == HAL_OK)
|
||||
{
|
||||
retval = Flash_TransferFullPage(ValidPage,NewPage,true,VirtAddress);
|
||||
}
|
||||
}
|
||||
/* Return last operation flash status */
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,59 @@
|
||||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file EEPROM_Emulation/inc/eeprom.h
|
||||
* @author MCD Application Team
|
||||
* @version V1.0.0
|
||||
* @date 10-October-2011
|
||||
* @brief This file contains all the functions prototypes for the EEPROM
|
||||
* emulation firmware library.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __UHSDR_FLASH_H
|
||||
#define __UHSDR_FLASH_H
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
#if defined(STM32F4) || defined(STM32F7)
|
||||
/* Define the size of the sectors to be used */
|
||||
#define PAGE_SIZE ((uint32_t)0x4000) /* Page size = 16KByte */
|
||||
|
||||
|
||||
/* EEPROM start address in Flash */
|
||||
#define EEPROM_START_ADDRESS ((uint32_t)0x08008000) /* EEPROM emulation start address:
|
||||
from sector2 : after 32KByte of used
|
||||
Flash memory */
|
||||
#define PAGE0_ID FLASH_SECTOR_2
|
||||
#define PAGE1_ID FLASH_SECTOR_3
|
||||
#elif defined(STM32H7)
|
||||
/* Define the size of the sectors to be used */
|
||||
#define PAGE_SIZE (uint32_t)0x20000 /* Page size = 128KByte */
|
||||
/* EEPROM start address in Flash */
|
||||
#define EEPROM_START_ADDRESS ((uint32_t)0x08020000) /* EEPROM emulation start address:
|
||||
from sector1 : after 128KByte of used
|
||||
Flash memory */
|
||||
#define PAGE0_ID FLASH_SECTOR_1
|
||||
#define PAGE1_ID FLASH_SECTOR_2
|
||||
#endif
|
||||
|
||||
|
||||
uint16_t Flash_Init(void);
|
||||
uint16_t Flash_ReadVariable(uint16_t addr, uint16_t* value);
|
||||
uint16_t Flash_WriteVariable(uint16_t addr, uint16_t value);
|
||||
uint16_t Flash_UpdateVariable(uint16_t addr, uint16_t value);
|
||||
|
||||
#endif /* __UHSDR_FLASH_H */
|
||||
|
||||
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
||||
Reference in New Issue
Block a user