first commit

This commit is contained in:
2022-08-24 08:41:00 +02:00
commit 5765dbd675
2497 changed files with 2244854 additions and 0 deletions
@@ -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>&copy; 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, &sectorError);
}
/**
* 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>&copy; 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****/