c2dcd70b2a
The choice for Trim in mixers will be: OFF / ON / Rud / Ele / Thr / Ail EEPROM formatted on ARM when invalid EEPROM No EEPROM format when ARM board USB powered
907 lines
23 KiB
C++
907 lines
23 KiB
C++
/*
|
|
* Author - Erez Raviv <erezraviv@gmail.com>
|
|
*
|
|
* Based on th9x -> http://code.google.com/p/th9x/
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU 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.
|
|
*
|
|
*/
|
|
|
|
|
|
#include <stdint.h>
|
|
#include "open9x.h"
|
|
#include "stdio.h"
|
|
#include "inttypes.h"
|
|
#include "string.h"
|
|
|
|
volatile uint32_t Spi_complete ;
|
|
uint8_t s_eeDirtyMsk;
|
|
uint16_t s_eeDirtyTime10ms;
|
|
|
|
// Logic for storing to EERPOM/loading from EEPROM
|
|
// If main needs to wait for the eeprom, call mainsequence without actioning menus
|
|
// General configuration
|
|
// 'main' set flag STORE_GENERAL
|
|
// 'eeCheck' sees flag STORE_GENERAL, copies data, starts 2 second timer, clears flag STORE_GENERAL
|
|
// 'eeCheck' sees 2 second timer expire, locks copy, initiates write, enters WRITE_GENERAL mode
|
|
// 'eeCheck' completes write, unlocks copy, exits WRITE_GENERAL mode
|
|
|
|
// 'main' set flag STORE_MODEL(n)
|
|
|
|
// 'main' set flag STORE_MODEL_TRIM(n)
|
|
|
|
|
|
// 'main' needs to load a model
|
|
|
|
|
|
// These may not be needed, or might just be smaller
|
|
uint8_t Spi_tx_buf[24] ;
|
|
uint8_t Spi_rx_buf[24] ;
|
|
|
|
|
|
struct t_file_entry File_system[MAX_MODELS+1] ;
|
|
|
|
char ModelNames[MAX_MODELS][sizeof(g_model.name)] ; // Allow for general
|
|
|
|
// TODO check everything here
|
|
uint8_t Eeprom32_process_state ;
|
|
uint8_t Eeprom32_state_after_erase ;
|
|
uint8_t Eeprom32_write_pending ;
|
|
uint8_t Eeprom32_file_index ;
|
|
uint8_t *Eeprom32_buffer_address ;
|
|
uint8_t *Eeprom32_source_address ;
|
|
uint32_t Eeprom32_address ;
|
|
uint32_t Eeprom32_data_size ;
|
|
|
|
#define EE_NOWAIT 1
|
|
|
|
void eeDirty(uint8_t msk)
|
|
{
|
|
s_eeDirtyMsk |= msk;
|
|
s_eeDirtyTime10ms = get_tmr10ms() ;
|
|
}
|
|
|
|
void handle_serial( void ) ;
|
|
|
|
uint32_t get_current_block_number( uint32_t block_no, uint16_t *p_size, uint32_t *p_seq ) ;
|
|
void read32_eeprom_data( uint32_t eeAddress, register uint8_t *buffer, uint32_t size, uint32_t immediate=0 ) ;
|
|
void write32_eeprom_block( uint32_t eeAddress, register uint8_t *buffer, uint32_t size, uint32_t immediate=0 ) ;
|
|
void ee32_read_model_names( void ) ;
|
|
void ee32LoadModelName(uint8_t id, char *buf, uint8_t len) ;
|
|
|
|
// New file system
|
|
|
|
// Start with 16 model memories, initial test uses 34 and 35 for these
|
|
// Blocks 0 and 1, general
|
|
// Blocks 2 and 3, model 1
|
|
// Blocks 4 and 5, model 2 etc
|
|
// Blocks 32 and 33, model 16
|
|
|
|
uint8_t Current_general_block ; // 0 or 1 is active block
|
|
uint8_t Other_general_block_blank ;
|
|
|
|
struct t_eeprom_header
|
|
{
|
|
uint32_t sequence_no ; // sequence # to decide which block is most recent
|
|
uint16_t data_size ; // # bytes in data area
|
|
uint8_t flags ;
|
|
uint8_t hcsum ;
|
|
} ;
|
|
|
|
#define EEPROM_BUFFER_SIZE ((sizeof(ModelData) + sizeof( struct t_eeprom_header ) + 3)/4)
|
|
|
|
struct t_eeprom_buffer
|
|
{
|
|
struct t_eeprom_header header ;
|
|
union t_eeprom_data
|
|
{
|
|
EEGeneral general_data ;
|
|
ModelData model_data ;
|
|
uint32_t words[ EEPROM_BUFFER_SIZE ] ;
|
|
} data ;
|
|
} Eeprom_buffer ;
|
|
|
|
#define EEPROM_BUFFER_SIZE ((sizeof(ModelData) + sizeof( struct t_eeprom_header ) + 3)/4)
|
|
|
|
void eeDeleteModel(uint8_t id)
|
|
{
|
|
eeCheck(true);
|
|
|
|
memset(ModelNames[id], 0, sizeof(g_model.name));
|
|
|
|
Eeprom32_source_address = (uint8_t *)&g_model ; // Get data from here
|
|
Eeprom32_data_size = 0 ; // This much
|
|
Eeprom32_file_index = id + 1 ; // This file system entry
|
|
Eeprom32_process_state = E32_BLANKCHECK ;
|
|
eeWaitFinished();
|
|
}
|
|
|
|
bool eeCopyModel(uint8_t dst, uint8_t src)
|
|
{
|
|
// eeCheck(true) should have been called before entering here
|
|
|
|
uint16_t size = File_system[src+1].size ;
|
|
read32_eeprom_data( (File_system[src+1].block_no << 12) + sizeof( struct t_eeprom_header), ( uint8_t *)&Eeprom_buffer.data.model_data, size) ;
|
|
|
|
if (size > sizeof(g_model.name))
|
|
memcpy(ModelNames[dst], Eeprom_buffer.data.model_data.name, sizeof(g_model.name));
|
|
else
|
|
memset(ModelNames[dst], 0, sizeof(g_model.name));
|
|
|
|
Eeprom32_source_address = (uint8_t *)&Eeprom_buffer.data.model_data; // Get data from here
|
|
Eeprom32_data_size = sizeof(g_model) ; // This much
|
|
Eeprom32_file_index = dst + 1 ; // This file system entry
|
|
Eeprom32_process_state = E32_BLANKCHECK ;
|
|
eeWaitFinished();
|
|
return true;
|
|
}
|
|
|
|
void eeSwapModels(uint8_t id1, uint8_t id2)
|
|
{
|
|
// eeCheck(true) should have been called before entering here
|
|
|
|
uint16_t id2_size = File_system[id2+1].size;
|
|
uint32_t id2_block_no = File_system[id2+1].block_no;
|
|
|
|
eeCopyModel(id2, id1);
|
|
|
|
// block_no(id1) has been shifted now, but we have the size
|
|
|
|
// TODO flash saving with function above ...
|
|
if (id2_size > sizeof(g_model.name)) {
|
|
read32_eeprom_data( (id2_block_no << 12) + sizeof( struct t_eeprom_header), ( uint8_t *)&Eeprom_buffer.data.model_data, id2_size);
|
|
memcpy(ModelNames[id1], Eeprom_buffer.data.model_data.name, sizeof(g_model.name));
|
|
}
|
|
else {
|
|
memset(ModelNames[id1], 0, sizeof(g_model.name));
|
|
}
|
|
|
|
Eeprom32_source_address = (uint8_t *)&Eeprom_buffer.data.model_data; // Get data from here
|
|
Eeprom32_data_size = id2_size ; // This much
|
|
Eeprom32_file_index = id1 + 1 ; // This file system entry
|
|
Eeprom32_process_state = E32_BLANKCHECK ;
|
|
eeWaitFinished();
|
|
}
|
|
|
|
uint32_t spi_PDC_action( register uint8_t *command, register uint8_t *tx, register uint8_t *rx, register uint32_t comlen, register uint32_t count )
|
|
{
|
|
#ifndef SIMU
|
|
|
|
register Spi *spiptr ;
|
|
register uint32_t condition ;
|
|
static uint8_t discard_rx_command[4] ;
|
|
|
|
// PMC->PMC_PCER0 |= 0x00200000L ; // Enable peripheral clock to SPI
|
|
|
|
Spi_complete = 0 ;
|
|
if ( comlen > 4 )
|
|
{
|
|
Spi_complete = 1 ;
|
|
return 0x4FFFF ;
|
|
}
|
|
condition = SPI_SR_TXEMPTY ;
|
|
spiptr = SPI ;
|
|
spiptr->SPI_CR = 1 ; // Enable
|
|
(void) spiptr->SPI_RDR ; // Dump any rx data
|
|
(void) spiptr->SPI_SR ; // Clear error flags
|
|
spiptr->SPI_RPR = (uint32_t)discard_rx_command ;
|
|
spiptr->SPI_RCR = comlen ;
|
|
if ( rx )
|
|
{
|
|
spiptr->SPI_RNPR = (uint32_t)rx ;
|
|
spiptr->SPI_RNCR = count ;
|
|
condition = SPI_SR_RXBUFF ;
|
|
}
|
|
spiptr->SPI_TPR = (uint32_t)command ;
|
|
spiptr->SPI_TCR = comlen ;
|
|
if ( tx )
|
|
{
|
|
spiptr->SPI_TNPR = (uint32_t)tx ;
|
|
}
|
|
else
|
|
{
|
|
spiptr->SPI_TNPR = (uint32_t)rx ;
|
|
}
|
|
spiptr->SPI_TNCR = count ;
|
|
|
|
spiptr->SPI_PTCR = SPI_PTCR_RXTEN | SPI_PTCR_TXTEN ; // Start transfers
|
|
|
|
// Wait for things to get started, avoids early interrupt
|
|
for ( count = 0 ; count < 1000 ; count += 1 )
|
|
{
|
|
if ( ( spiptr->SPI_SR & SPI_SR_TXEMPTY ) == 0 )
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
spiptr->SPI_IER = condition ;
|
|
|
|
#endif
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
uint32_t eeprom_write_one( uint8_t byte, uint8_t count )
|
|
{
|
|
#ifndef SIMU
|
|
register Spi *spiptr;
|
|
register uint32_t result;
|
|
|
|
spiptr = SPI;
|
|
spiptr->SPI_CR = 1; // Enable
|
|
(void) spiptr->SPI_RDR; // Dump any rx data
|
|
|
|
spiptr->SPI_TDR = byte;
|
|
|
|
result = 0;
|
|
while ((spiptr->SPI_SR & SPI_SR_RDRF) == 0) {
|
|
// wait for received
|
|
if (++result > 10000) {
|
|
break;
|
|
}
|
|
}
|
|
if (count == 0) {
|
|
spiptr->SPI_CR = 2; // Disable
|
|
return spiptr->SPI_RDR;
|
|
}
|
|
(void) spiptr->SPI_RDR; // Dump the rx data
|
|
spiptr->SPI_TDR = 0;
|
|
result = 0;
|
|
while ((spiptr->SPI_SR & SPI_SR_RDRF) == 0) {
|
|
// wait for received
|
|
if (++result > 10000) {
|
|
break;
|
|
}
|
|
}
|
|
spiptr->SPI_CR = 2; // Disable
|
|
return spiptr->SPI_RDR ;
|
|
#else
|
|
return !Spi_complete;
|
|
#endif
|
|
}
|
|
|
|
void eeprom_write_enable()
|
|
{
|
|
eeprom_write_one( 6, 0 ) ;
|
|
}
|
|
|
|
uint32_t eeprom_read_status()
|
|
{
|
|
return eeprom_write_one( 5, 1 ) ;
|
|
}
|
|
|
|
// Read eeprom data starting at random address
|
|
void read32_eeprom_data( uint32_t eeAddress, register uint8_t *buffer, uint32_t size, uint32_t immediate )
|
|
{
|
|
#ifdef SIMU
|
|
assert(size);
|
|
eeprom_pointer = eeAddress;
|
|
eeprom_buffer_data = (char*)buffer;
|
|
eeprom_buffer_size = size;
|
|
eeprom_read_operation = true;
|
|
Spi_complete = false;
|
|
sem_post(&eeprom_write_sem);
|
|
#else
|
|
register uint8_t *p = Spi_tx_buf ;
|
|
*p = 3 ; // Read command
|
|
*(p+1) = eeAddress >> 16 ;
|
|
*(p+2) = eeAddress >> 8 ;
|
|
*(p+3) = eeAddress ; // 3 bytes address
|
|
spi_PDC_action( p, 0, buffer, 4, size ) ;
|
|
#endif
|
|
|
|
if (immediate )
|
|
return ;
|
|
|
|
while (!Spi_complete) {
|
|
#ifdef SIMU
|
|
sleep(5/*ms*/);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void write32_eeprom_block( uint32_t eeAddress, register uint8_t *buffer, uint32_t size, uint32_t immediate )
|
|
{
|
|
#ifdef SIMU
|
|
assert(size);
|
|
eeprom_pointer = eeAddress;
|
|
eeprom_buffer_data = (char*)buffer;
|
|
eeprom_buffer_size = size+1;
|
|
eeprom_read_operation = false;
|
|
Spi_complete = false;
|
|
sem_post(&eeprom_write_sem);
|
|
#else
|
|
eeprom_write_enable();
|
|
|
|
register uint8_t *p = Spi_tx_buf;
|
|
*p = 2; // Write command
|
|
*(p + 1) = eeAddress >> 16;
|
|
*(p + 2) = eeAddress >> 8;
|
|
*(p + 3) = eeAddress; // 3 bytes address
|
|
spi_PDC_action(p, buffer, 0, 4, size);
|
|
#endif
|
|
|
|
if (immediate)
|
|
return;
|
|
|
|
while (!Spi_complete) {
|
|
#ifdef SIMU
|
|
sleep(5/*ms*/);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
uint8_t byte_checksum( uint8_t *p, uint32_t size )
|
|
{
|
|
uint32_t csum ;
|
|
|
|
csum = 0 ;
|
|
while( size )
|
|
{
|
|
csum += *p++ ;
|
|
size -= 1 ;
|
|
}
|
|
return csum ;
|
|
}
|
|
|
|
uint32_t ee32_check_header( struct t_eeprom_header *hptr )
|
|
{
|
|
uint8_t csum ;
|
|
|
|
csum = byte_checksum( ( uint8_t *) hptr, 7 ) ;
|
|
if ( csum == hptr->hcsum )
|
|
{
|
|
return 1 ;
|
|
}
|
|
return 0 ;
|
|
}
|
|
|
|
// Pass in an even block number, this and the next block will be checked
|
|
// to see which is the most recent, the block_no of the most recent
|
|
// is returned, with the corresponding data size if required
|
|
// and the sequence number if required
|
|
uint32_t get_current_block_number( uint32_t block_no, uint16_t *p_size, uint32_t *p_seq )
|
|
{
|
|
struct t_eeprom_header b0 ;
|
|
struct t_eeprom_header b1 ;
|
|
uint32_t sequence_no ;
|
|
uint16_t size ;
|
|
read32_eeprom_data( block_no << 12, ( uint8_t *)&b0, sizeof(b0) ) ; // Sequence # 0
|
|
read32_eeprom_data( (block_no+1) << 12, ( uint8_t *)&b1, sizeof(b1) ) ; // Sequence # 1
|
|
|
|
if ( ee32_check_header( &b0 ) == 0 )
|
|
{
|
|
b0.sequence_no = 0 ;
|
|
b0.data_size = 0 ;
|
|
b0.flags = 0 ;
|
|
}
|
|
|
|
size = b0.data_size ;
|
|
sequence_no = b0.sequence_no ;
|
|
if ( ee32_check_header( &b0 ) == 0 )
|
|
{
|
|
if ( ee32_check_header( &b1 ) != 0 )
|
|
{
|
|
size = b1.data_size ;
|
|
sequence_no = b1.sequence_no ;
|
|
block_no += 1 ;
|
|
}
|
|
else
|
|
{
|
|
size = 0 ;
|
|
sequence_no = 1 ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ee32_check_header( &b1 ) != 0 )
|
|
{
|
|
if ( b1.sequence_no > b0.sequence_no )
|
|
{
|
|
size = b1.data_size ;
|
|
sequence_no = b1.sequence_no ;
|
|
block_no += 1 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( size == 0xFFFF )
|
|
{
|
|
size = 0 ;
|
|
}
|
|
if ( p_size )
|
|
{
|
|
*p_size = size ;
|
|
}
|
|
if ( sequence_no == 0xFFFFFFFF )
|
|
{
|
|
sequence_no = 0 ;
|
|
}
|
|
if ( p_seq )
|
|
{
|
|
*p_seq = sequence_no ;
|
|
}
|
|
// Block_needs_erasing = erase ;
|
|
|
|
return block_no ;
|
|
}
|
|
|
|
bool ee32LoadGeneral()
|
|
{
|
|
uint16_t size ;
|
|
|
|
size = File_system[0].size ;
|
|
|
|
memset(&g_eeGeneral, 0, sizeof(EEGeneral));
|
|
|
|
if (size > sizeof(EEGeneral)) {
|
|
size = sizeof(EEGeneral) ;
|
|
}
|
|
|
|
if (size) {
|
|
read32_eeprom_data( ( File_system[0].block_no << 12) + sizeof( struct t_eeprom_header), ( uint8_t *)&g_eeGeneral, size) ;
|
|
}
|
|
|
|
if (g_eeGeneral.myVers == EEPROM_VER) {
|
|
uint16_t sum = evalChkSum();
|
|
if (g_eeGeneral.chkSum == sum) {
|
|
return true;
|
|
}
|
|
}
|
|
#ifdef SIMU
|
|
else {
|
|
printf("EEPROM version %d instead of %d\n", g_eeGeneral.myVers, EEPROM_VER);
|
|
fflush(stdout);
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
void eeLoadModel(uint8_t id)
|
|
{
|
|
uint16_t size ;
|
|
|
|
if (id<MAX_MODELS) {
|
|
|
|
size = File_system[id+1].size ;
|
|
|
|
memset(&g_model, 0, sizeof(g_model));
|
|
|
|
#ifdef SIMU
|
|
if (size > 0 && size != sizeof(g_model)) {
|
|
printf("Model data read=%d bytes vs %d bytes\n", size, (int)sizeof(ModelData));
|
|
}
|
|
#endif
|
|
|
|
if (size > sizeof(g_model)) {
|
|
size = sizeof(g_model) ;
|
|
}
|
|
|
|
if(size < 256) { // if not loaded a fair amount
|
|
modelDefault(id) ;
|
|
eeCheck(true);
|
|
}
|
|
else {
|
|
read32_eeprom_data( ( File_system[id+1].block_no << 12) + sizeof( struct t_eeprom_header), ( uint8_t *)&g_model, size) ;
|
|
}
|
|
|
|
resetProto();
|
|
resetAll();
|
|
|
|
#ifdef SDCARD
|
|
initLogs();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
bool eeModelExists(uint8_t id)
|
|
{
|
|
return ( File_system[id+1].size > 0 ) ;
|
|
}
|
|
|
|
void ee32LoadModelName(uint8_t id, char *buf, uint8_t len)
|
|
{
|
|
if (id < MAX_MODELS) {
|
|
id += 1;
|
|
memset(buf, 0, len);
|
|
if (File_system[id].size > sizeof(g_model.name) ) {
|
|
read32_eeprom_data( ( File_system[id].block_no << 12) + 8, ( uint8_t *)buf, sizeof(g_model.name)) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
void eeReadAll()
|
|
{
|
|
if (!ee32LoadGeneral() )
|
|
{
|
|
generalDefault();
|
|
|
|
alert(STR_BADEEPROMDATA);
|
|
message(STR_MESSAGE, STR_EEPROMFORMATTING, NULL, NULL);
|
|
|
|
modelDefault(0);
|
|
|
|
if (check_soft_power() < e_power_usb) { // Usb on or power off
|
|
/* we remove all models */
|
|
for (uint32_t i=0; i<MAX_MODELS; i++)
|
|
eeDeleteModel(i);
|
|
|
|
STORE_GENERALVARS;
|
|
STORE_MODELVARS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
eeLoadModel(g_eeGeneral.currModel);
|
|
ee32_read_model_names() ;
|
|
}
|
|
|
|
stickMode = g_eeGeneral.stickMode; // TODO common!
|
|
}
|
|
|
|
uint32_t spi_operation( register uint8_t *tx, register uint8_t *rx, register uint32_t count )
|
|
{
|
|
register Spi *spiptr;
|
|
register uint32_t result;
|
|
|
|
// PMC->PMC_PCER0 |= 0x00200000L ; // Enable peripheral clock to SPI
|
|
|
|
result = 0;
|
|
spiptr = SPI;
|
|
spiptr->SPI_CR = 1; // Enable
|
|
(void) spiptr->SPI_RDR; // Dump any rx data
|
|
while (count) {
|
|
result = 0;
|
|
while ((spiptr->SPI_SR & SPI_SR_TXEMPTY) == 0) {
|
|
// wait
|
|
if (++result > 10000) {
|
|
result = 0xFFFF;
|
|
break;
|
|
}
|
|
}
|
|
if (result > 10000) {
|
|
break;
|
|
}
|
|
// if ( count == 1 )
|
|
// {
|
|
// spiptr->SPI_CR = SPI_CR_LASTXFER ; // LastXfer bit
|
|
// }
|
|
spiptr->SPI_TDR = *tx++;
|
|
result = 0;
|
|
while ((spiptr->SPI_SR & SPI_SR_RDRF) == 0) {
|
|
// wait for received
|
|
if (++result > 10000) {
|
|
result = 0x2FFFF;
|
|
break;
|
|
}
|
|
}
|
|
if (result > 10000) {
|
|
break;
|
|
}
|
|
*rx++ = spiptr->SPI_RDR;
|
|
count -= 1;
|
|
}
|
|
if (result <= 10000) {
|
|
result = 0;
|
|
}
|
|
spiptr->SPI_CR = 2; // Disable
|
|
|
|
// Power save
|
|
// PMC->PMC_PCER0 &= ~0x00200000L ; // Disable peripheral clock to SPI
|
|
|
|
return result ;
|
|
}
|
|
|
|
// SPI i/f to EEPROM (4Mb)
|
|
// Peripheral ID 21 (0x00200000)
|
|
// Connections:
|
|
// SS PA11 (peripheral A)
|
|
// MISO PA12 (peripheral A)
|
|
// MOSI PA13 (peripheral A)
|
|
// SCK PA14 (peripheral A)
|
|
// Set clock to 3 MHz, AT25 device is rated to 70MHz, 18MHz would be better
|
|
void init_spi()
|
|
{
|
|
register Spi *spiptr ;
|
|
register uint32_t timer ;
|
|
register uint8_t *p ;
|
|
uint8_t spi_buf[4] ;
|
|
|
|
PMC->PMC_PCER0 |= 0x00200000L ; // Enable peripheral clock to SPI
|
|
/* Configure PIO */
|
|
configure_pins( 0x00007800, PIN_PERIPHERAL | PIN_INPUT | PIN_PER_A | PIN_PORTA | PIN_NO_PULLUP ) ;
|
|
|
|
spiptr = SPI ;
|
|
timer = ( Master_frequency / 3000000 ) << 8 ; // Baud rate 3Mb/s
|
|
spiptr->SPI_MR = 0x14000011 ; // 0001 0100 0000 0000 0000 0000 0001 0001 Master
|
|
spiptr->SPI_CSR[0] = 0x01180009 | timer ; // 0000 0001 0001 1000 xxxx xxxx 0000 1001
|
|
NVIC_EnableIRQ(SPI_IRQn) ;
|
|
|
|
p = spi_buf ;
|
|
|
|
// *p = 0x39 ; // Unprotect sector command
|
|
// *(p+1) = 0 ;
|
|
// *(p+2) = 0 ;
|
|
// *(p+3) = 0 ; // 3 bytes address
|
|
|
|
// spi_operation( p, spi_buf, 4 ) ;
|
|
|
|
eeprom_write_enable() ;
|
|
|
|
*p = 1 ; // Write status register command
|
|
*(p+1) = 0 ;
|
|
spi_operation( p, spi_buf, 2 ) ;
|
|
}
|
|
|
|
#ifndef SIMU
|
|
extern "C" void SPI_IRQHandler()
|
|
{
|
|
register Spi *spiptr ;
|
|
|
|
spiptr = SPI ;
|
|
SPI->SPI_IDR = 0x07FF ; // All interrupts off
|
|
spiptr->SPI_CR = 2 ; // Disable
|
|
(void) spiptr->SPI_RDR ; // Dump any rx data
|
|
(void) spiptr->SPI_SR ; // Clear error flags
|
|
spiptr->SPI_PTCR = SPI_PTCR_RXTDIS | SPI_PTCR_TXTDIS ; // Stop tramsfers
|
|
Spi_complete = 1 ; // Indicate completion
|
|
|
|
// Power save
|
|
// PMC->PMC_PCER0 &= ~0x00200000L ; // Disable peripheral clock to SPI
|
|
}
|
|
#endif
|
|
|
|
void end_spi()
|
|
{
|
|
SPI->SPI_CR = 2 ; // Disable
|
|
SPI->SPI_IDR = 0x07FF ; // All interrupts off
|
|
NVIC_DisableIRQ(SPI_IRQn) ;
|
|
}
|
|
|
|
void eeWaitFinished()
|
|
{
|
|
while (Eeprom32_process_state != E32_IDLE) {
|
|
ee32_process();
|
|
#ifdef SIMU
|
|
sleep(5/*ms*/);
|
|
#endif
|
|
// TODO perMain()?
|
|
}
|
|
}
|
|
|
|
void eeCheck(bool immediately)
|
|
{
|
|
if (immediately) {
|
|
eeWaitFinished();
|
|
}
|
|
|
|
if (s_eeDirtyMsk & EE_GENERAL) {
|
|
s_eeDirtyMsk -= EE_GENERAL;
|
|
Eeprom32_source_address = (uint8_t *)&g_eeGeneral ; // Get data from here
|
|
Eeprom32_data_size = sizeof(g_eeGeneral) ; // This much
|
|
Eeprom32_file_index = 0 ; // This file system entry
|
|
Eeprom32_process_state = E32_BLANKCHECK ;
|
|
if (immediately)
|
|
eeWaitFinished();
|
|
else
|
|
return;
|
|
}
|
|
|
|
if (s_eeDirtyMsk & EE_MODEL) {
|
|
s_eeDirtyMsk -= EE_MODEL;
|
|
Eeprom32_source_address = (uint8_t *)&g_model ; // Get data from here
|
|
Eeprom32_data_size = sizeof(g_model) ; // This much
|
|
Eeprom32_file_index = g_eeGeneral.currModel + 1 ; // This file system entry
|
|
Eeprom32_process_state = E32_BLANKCHECK ;
|
|
if (immediately)
|
|
eeWaitFinished();
|
|
}
|
|
}
|
|
|
|
void ee32_process()
|
|
{
|
|
register uint8_t *p ;
|
|
register uint8_t *q ;
|
|
register uint32_t x ;
|
|
register uint32_t eeAddress ;
|
|
|
|
if ( Eeprom32_process_state == E32_BLANKCHECK ) {
|
|
eeAddress = File_system[Eeprom32_file_index].block_no ^ 1 ;
|
|
eeAddress <<= 12 ; // Block start address
|
|
Eeprom32_address = eeAddress ; // Where to put new data
|
|
#if 0
|
|
x = Eeprom32_data_size + sizeof( struct t_eeprom_header ) ; // Size needing to be checked
|
|
p = (uint8_t *) &Eeprom_buffer ;
|
|
read32_eeprom_data( eeAddress, p, x, EE_NOWAIT ) ;
|
|
#endif
|
|
Eeprom32_process_state = E32_READSENDING ;
|
|
}
|
|
|
|
if ( Eeprom32_process_state == E32_READSENDING )
|
|
{
|
|
#if 0
|
|
if ( Spi_complete )
|
|
{
|
|
uint32_t blank = 1 ;
|
|
x = Eeprom32_data_size + sizeof( struct t_eeprom_header ) ; // Size needing to be checked
|
|
p = (uint8_t *) &Eeprom_buffer ;
|
|
while ( x )
|
|
{
|
|
if ( *p++ != 0xFF )
|
|
{
|
|
blank = 0 ;
|
|
break ;
|
|
}
|
|
x -= 1 ;
|
|
}
|
|
// If not blank, sort erasing here
|
|
if ( blank )
|
|
{
|
|
Eeprom32_state_after_erase = E32_IDLE ; // TODO really needed?
|
|
Eeprom32_process_state = E32_WRITESTART ;
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
#ifdef SIMU
|
|
Eeprom32_process_state = E32_WRITESTART ;
|
|
#else
|
|
eeAddress = Eeprom32_address ;
|
|
eeprom_write_enable() ;
|
|
p = Spi_tx_buf ;
|
|
*p = 0x20 ; // Block Erase command
|
|
*(p+1) = eeAddress >> 16 ;
|
|
*(p+2) = eeAddress >> 8 ;
|
|
*(p+3) = eeAddress ; // 3 bytes address
|
|
spi_PDC_action( p, 0, 0, 4, 0 ) ;
|
|
Eeprom32_process_state = E32_ERASESENDING ;
|
|
Eeprom32_state_after_erase = E32_WRITESTART ;
|
|
#endif
|
|
// }
|
|
// }
|
|
}
|
|
|
|
if ( Eeprom32_process_state == E32_WRITESTART )
|
|
{
|
|
uint32_t total_size ;
|
|
p = Eeprom32_source_address;
|
|
q = (uint8_t *) &Eeprom_buffer.data;
|
|
if (p != q) {
|
|
// TODO why not memcpy
|
|
for (x = 0; x < Eeprom32_data_size; x += 1) {
|
|
*q++ = *p++; // Copy the data to temp buffer
|
|
}
|
|
}
|
|
Eeprom_buffer.header.sequence_no = ++File_system[Eeprom32_file_index].sequence_no;
|
|
File_system[Eeprom32_file_index].size = Eeprom_buffer.header.data_size = Eeprom32_data_size;
|
|
Eeprom_buffer.header.flags = 0;
|
|
Eeprom_buffer.header.hcsum = byte_checksum((uint8_t *) &Eeprom_buffer, 7);
|
|
total_size = Eeprom32_data_size + sizeof(struct t_eeprom_header);
|
|
eeAddress = Eeprom32_address; // Block start address
|
|
x = total_size / 256; // # sub blocks
|
|
x <<= 8; // to offset address
|
|
eeAddress += x; // Add it in
|
|
p = (uint8_t *) &Eeprom_buffer;
|
|
p += x; // Add offset
|
|
x = total_size % 256; // Size of last bit
|
|
if (x == 0) // Last bit empty
|
|
{
|
|
x = 256;
|
|
p -= x;
|
|
eeAddress -= x;
|
|
}
|
|
Eeprom32_buffer_address = p;
|
|
Eeprom32_address = eeAddress;
|
|
write32_eeprom_block(eeAddress, p, x, EE_NOWAIT);
|
|
Eeprom32_process_state = E32_WRITESENDING ;
|
|
}
|
|
|
|
if ( Eeprom32_process_state == E32_WRITESENDING )
|
|
{
|
|
if ( Spi_complete )
|
|
{
|
|
Eeprom32_process_state = E32_WRITEWAITING ;
|
|
}
|
|
}
|
|
|
|
if ( Eeprom32_process_state == E32_WRITEWAITING )
|
|
{
|
|
x = eeprom_read_status() ;
|
|
if ( ( x & 1 ) == 0 )
|
|
{
|
|
if ( ( Eeprom32_address & 0x0FFF ) != 0 ) // More to write
|
|
{
|
|
Eeprom32_address -= 256 ;
|
|
Eeprom32_buffer_address -= 256 ;
|
|
write32_eeprom_block( Eeprom32_address, Eeprom32_buffer_address, 256, EE_NOWAIT ) ;
|
|
Eeprom32_process_state = E32_WRITESENDING ;
|
|
}
|
|
else
|
|
{
|
|
File_system[Eeprom32_file_index].block_no ^= 1 ; // This is now the current block
|
|
#if 0
|
|
// now erase the other block
|
|
File_system[Eeprom32_file_index].block_no ^= 1 ; // This is now the current block
|
|
eeAddress = Eeprom32_address ^ 0x00001000 ; // Address of block to erase
|
|
eeprom_write_enable() ;
|
|
p = Spi_tx_buf ;
|
|
*p = 0x20 ; // Block Erase command
|
|
*(p+1) = eeAddress >> 16 ;
|
|
*(p+2) = eeAddress >> 8 ;
|
|
*(p+3) = eeAddress ; // 3 bytes address
|
|
spi_PDC_action( p, 0, 0, 4, 0 ) ;
|
|
Eeprom32_process_state = E32_ERASESENDING ;
|
|
Eeprom32_state_after_erase = E32_IDLE ;
|
|
#endif
|
|
Eeprom32_process_state = E32_IDLE ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( Eeprom32_process_state == E32_ERASESENDING )
|
|
{
|
|
if ( Spi_complete )
|
|
{
|
|
Eeprom32_process_state = E32_ERASEWAITING ;
|
|
}
|
|
}
|
|
|
|
if ( Eeprom32_process_state == E32_ERASEWAITING )
|
|
{
|
|
x = eeprom_read_status() ;
|
|
if ( ( x & 1 ) == 0 )
|
|
{ // Command finished
|
|
Eeprom32_process_state = Eeprom32_state_after_erase ;
|
|
}
|
|
}
|
|
}
|
|
|
|
void fill_file_index()
|
|
{
|
|
for (uint32_t i = 0 ; i < MAX_MODELS + 1 ; i += 1 )
|
|
{
|
|
File_system[i].block_no = get_current_block_number( i * 2, &File_system[i].size, &File_system[i].sequence_no ) ;
|
|
}
|
|
}
|
|
|
|
void ee32_read_model_names()
|
|
{
|
|
for (uint32_t i=0; i<MAX_MODELS; i++)
|
|
{
|
|
ee32LoadModelName(i, ModelNames[i], sizeof(g_model.name));
|
|
}
|
|
}
|
|
|
|
void eeprom_init()
|
|
{
|
|
#ifndef SIMU
|
|
init_spi() ;
|
|
#endif
|
|
fill_file_index() ;
|
|
Eeprom32_process_state = E32_IDLE ;
|
|
}
|
|
|
|
uint32_t unprotect_eeprom()
|
|
{
|
|
register uint8_t *p;
|
|
|
|
eeprom_write_enable();
|
|
|
|
p = Spi_tx_buf;
|
|
*p = 0x39; // Unprotect sector command
|
|
*(p + 1) = 0;
|
|
*(p + 2) = 0;
|
|
*(p + 3) = 0; // 3 bytes address
|
|
|
|
return spi_operation( p, Spi_rx_buf, 4 ) ;
|
|
}
|
|
|