mirror of
https://github.com/eddyem/mmpp.git
synced 2025-12-06 10:35:16 +03:00
142 lines
5.2 KiB
C
142 lines
5.2 KiB
C
/*
|
|
* geany_encoding=koi8-r
|
|
* flash.c
|
|
*
|
|
* Copyright 2017 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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 General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
#include "stm32f0.h"
|
|
#include <string.h> // memcpy
|
|
|
|
#include "flash.h"
|
|
#include "usart.h"
|
|
|
|
// start of configuration data in flash (from 15kB, one kB size)
|
|
#define FLASH_CONF_START_ADDR ((uint32_t)0x08003C00)
|
|
static const int maxnum = 1024 / sizeof(user_conf);
|
|
|
|
// all denominators except Vdd by default are 10 (as Vdd stored as V*100, other data as V*10)
|
|
user_conf the_conf = {
|
|
.userconf_sz = sizeof(user_conf)
|
|
,.devID = 0
|
|
,.v12numerator = 1
|
|
,.v12denominator = 1
|
|
,.i12numerator = 1
|
|
,.i12denominator = 1
|
|
,.v33denominator = 1
|
|
,.v33numerator = 1
|
|
,.ESW_thres = 500
|
|
,.usartspd = (uint32_t)9600
|
|
,.motspd = {10, 10} // max speed: 300 steps per second, should be LESS than 1310!
|
|
,.maxsteps = {50000, 50000} // max steps from point to point
|
|
,.reverse = {0,0} // set DIR to this value when moving to '+'
|
|
,.intpullup = 1 // by default internal pullup @ Tx pin enabled
|
|
,.usteps = 16
|
|
,.accdecsteps = 100
|
|
};
|
|
|
|
static int erase_flash(void);
|
|
|
|
static int get_gooddata(){
|
|
user_conf *c = (user_conf*) FLASH_CONF_START_ADDR;
|
|
// have data - move it to `the_conf`
|
|
int idx;
|
|
for(idx = 0; idx < maxnum; ++idx){ // find current settings index - first good
|
|
uint16_t sz = c[idx].userconf_sz;
|
|
if(sz != sizeof(user_conf)){
|
|
if(sz == 0xffff) break; // first clear
|
|
else{
|
|
return -2; // flash corrupt, need to erase
|
|
}
|
|
}
|
|
}
|
|
return idx-1; // -1 if there's no data at all & flash is clear; maxnum-1 if flash is full
|
|
}
|
|
|
|
void get_userconf(){
|
|
user_conf *c = (user_conf*) FLASH_CONF_START_ADDR;
|
|
int idx = get_gooddata();
|
|
if(idx < 0) return; // no data stored
|
|
memcpy(&the_conf, &c[idx], sizeof(user_conf));
|
|
}
|
|
|
|
// store new configuration
|
|
// @return 0 if all OK
|
|
int store_userconf(){
|
|
int ret = 0;
|
|
user_conf *c = (user_conf*) FLASH_CONF_START_ADDR;
|
|
int idx = get_gooddata();
|
|
if(idx == -2 || idx == maxnum - 1){ // data corruption or there's no more place
|
|
idx = 0;
|
|
if(erase_flash()) return 1;
|
|
}else ++idx; // take next data position
|
|
if (FLASH->CR & FLASH_CR_LOCK){ // unloch flash
|
|
FLASH->KEYR = FLASH_FKEY1;
|
|
FLASH->KEYR = FLASH_FKEY2;
|
|
}
|
|
while (FLASH->SR & FLASH_SR_BSY);
|
|
if(FLASH->SR & FLASH_SR_WRPERR) return 1; // write protection
|
|
FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; // clear all flags
|
|
FLASH->CR |= FLASH_CR_PG;
|
|
uint16_t *data = (uint16_t*) &the_conf;
|
|
uint16_t *address = (uint16_t*) &c[idx];
|
|
uint32_t i, count = (1 + sizeof(user_conf)) / 2;
|
|
for (i = 0; i < count; ++i){
|
|
*(volatile uint16_t*)(address + i) = data[i];
|
|
while (FLASH->SR & FLASH_SR_BSY);
|
|
if(FLASH->SR & FLASH_SR_PGERR) ret = 1; // program error - meet not 0xffff
|
|
else while (!(FLASH->SR & FLASH_SR_EOP));
|
|
FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR;
|
|
}
|
|
FLASH->CR &= ~(FLASH_CR_PG);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int erase_flash(){
|
|
int ret = 0;
|
|
/* (1) Wait till no operation is on going */
|
|
/* (2) Clear error & EOP bits */
|
|
/* (3) Check that the Flash is unlocked */
|
|
/* (4) Perform unlock sequence */
|
|
while ((FLASH->SR & FLASH_SR_BSY) != 0){} /* (1) */
|
|
FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; /* (2) */
|
|
if ((FLASH->CR & FLASH_CR_LOCK) != 0){ /* (3) */
|
|
FLASH->KEYR = FLASH_FKEY1; /* (4) */
|
|
FLASH->KEYR = FLASH_FKEY2;
|
|
}
|
|
/* (1) Set the PER bit in the FLASH_CR register to enable page erasing */
|
|
/* (2) Program the FLASH_AR register to select a page to erase */
|
|
/* (3) Set the STRT bit in the FLASH_CR register to start the erasing */
|
|
/* (4) Wait until the EOP flag in the FLASH_SR register set */
|
|
/* (5) Clear EOP flag by software by writing EOP at 1 */
|
|
/* (6) Reset the PER Bit to disable the page erase */
|
|
FLASH->CR |= FLASH_CR_PER; /* (1) */
|
|
FLASH->AR = FLASH_CONF_START_ADDR; /* (2) */
|
|
FLASH->CR |= FLASH_CR_STRT; /* (3) */
|
|
while(!(FLASH->SR & FLASH_SR_EOP));
|
|
FLASH->SR |= FLASH_SR_EOP; /* (5)*/
|
|
if(FLASH->SR & FLASH_SR_WRPERR){ /* Check Write protection error */
|
|
ret = 1;
|
|
FLASH->SR |= FLASH_SR_WRPERR; /* Clear the flag by software by writing it at 1*/
|
|
}
|
|
FLASH->CR &= ~FLASH_CR_PER; /* (6) */
|
|
return ret;
|
|
}
|
|
|