changeset 27:5c9d2e3d6591

Add flashread/writeblock commands which read/write a block of data to flash with a CRC.
author Daniel O'Connor <darius@dons.net.au>
date Tue, 20 Nov 2012 21:54:06 +1030
parents 74efdb21ae5d
children 7f8e5780024b
files BSDmakefile flash.c flash.h hw.c
diffstat 4 files changed, 191 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/BSDmakefile	Sat Nov 17 18:03:48 2012 +1030
+++ b/BSDmakefile	Tue Nov 20 21:54:06 2012 +1030
@@ -15,7 +15,7 @@
 		system_stm32f10x.c \
 		touch.c
 
-STM32LIBS=	usart gpio rcc rtc pwr bkp fsmc spi tim i2c
+STM32LIBS=	usart gpio rcc rtc pwr bkp fsmc spi tim i2c crc
 
 .for f in ${STM32LIBS}
 SRCS+=		stm32f10x_${f}.c
--- a/flash.c	Sat Nov 17 18:03:48 2012 +1030
+++ b/flash.c	Tue Nov 20 21:54:06 2012 +1030
@@ -24,14 +24,80 @@
 
 #define RW_IDLE		0
 #define RW_RUNNING	1
-#define RW_IDLE		0
+
+/* Holds all the settings needed */
+typedef struct {
+    uint8_t	fermenter_ROM[8];
+    uint8_t	fridge_ROM[8];
+    uint8_t	ambient_ROM[8];
+    int16_t	target_temp;
+    uint16_t	hysteresis;
+    /* How much to under/overshoot on heating/cooling */
+    int16_t	minheatovershoot;
+    int16_t	mincoolovershoot;
+
+    /* Minimum time the cooler can be on/off */
+    int16_t	mincoolontime;
+    int16_t	mincoolofftime;
+
+    /* Minimum time the heater can be on/off */
+    int16_t	minheatontime;
+    int16_t	minheatofftime;
+
+#define TC_MODE_AUTO	'a'	/* Automatic control */
+#define TC_MODE_HEAT	'h'	/* Force heating */
+#define TC_MODE_COOL	'c'	/* Force cooling */
+#define TC_MODE_IDLE	'i'	/* Force idle */
+#define TC_MODE_NOTHING	'n'	/* Do nothing (like idle but log nothing) */
+    char	mode;
     
+    /* Bit patterns for various modes */
+    uint8_t	coolbits;
+    uint8_t	heatbits;
+    uint8_t	idlebits;
+
+    /* Check/stale times */
+    int16_t	check_interval;
+    int16_t	stale_factor;
+
+    /* Beep if stale */
+    int8_t	dobeep;
+
+    /* Pad to 4 bytes */
+    uint8_t	pad[1];
+    
+} __attribute__((packed, aligned(4))) settings_t;
+    
+const settings_t default_settings = {
+    .fermenter_ROM = { 0x10, 0x4c, 0x7d, 0x53, 0x01, 0x08, 0x00, 0xff },
+    .fridge_ROM =  { 0x10, 0x6f, 0x40, 0x53, 0x01, 0x08, 0x00, 0x16 },
+    .ambient_ROM = { 0x10, 0x76, 0x05, 0x53, 0x01, 0x08, 0x00, 0x8c },
+    .target_temp = 1000,
+    .hysteresis = 100,
+    .minheatovershoot = 50,
+    .mincoolovershoot = -50,
+    .mincoolontime = 300,
+    .mincoolofftime = 600,
+    .minheatontime = 60,
+    .minheatofftime = 60,
+    .mode = TC_MODE_AUTO,
+    .coolbits = 1 << 6,
+    .heatbits = 1<< 7,
+    .idlebits = 0x00,
+    .check_interval = 10,
+    .stale_factor = 3,
+    .dobeep = 0
+};
+
+/* RAM copy of setting */
+static settings_t ram_settings;
+
 static int writestate = RW_IDLE;
 static int readstate = RW_IDLE;
 
 void
 flashcmd(char **argv, int argc) {
-    uint8_t status, tmp;
+    uint8_t status, tmp, len;
     uint32_t addr;
     
     if (argc == 0) {
@@ -66,27 +132,37 @@
 	flash4kerase(addr);
 	printf("Erased 0x%x\r\n", (unsigned int)addr);
     } else if (!strcmp(argv[0], "rd")) {
-	if (argc != 2) {
+	if (argc < 2) {
+	    fputs("Incorrect number of arguments\r\n", stdout);
+	    return;
+	}
+	
+	addr = atoi(argv[1]);
+
+	if (argc > 2)
+	    len = atoi(argv[2]);
+	else
+	    len = 16;
+
+	flashstartread(addr);
+	
+	for (uint32_t i = 0; i < len; i++)
+	    printf("Read 0x%02x from 0x%06x\r\n", flashreadbyte(), (unsigned int)(addr + i));
+	flashstopread();
+	
+	fputs("\r\n", stdout);
+    } else if (!strcmp(argv[0], "wr")) {
+	if (argc < 2) {
 	    fputs("Incorrect number of arguments\r\n", stdout);
 	    return;
 	}
 
 	addr = atoi(argv[1]);
 
-	flashstartread(addr);
-	
-	for (int i = 0; i < 16; i++)
-	    printf("Read 0x%02x from 0x%06x\r\n", flashreadbyte(), (unsigned int)(addr + i));
-	flashstopread();
-	
-	fputs("\r\n", stdout);
-    } else if (!strcmp(argv[0], "wr")) {
-	if (argc != 2) {
-	    fputs("Incorrect number of arguments\r\n", stdout);
-	    return;
-	}
-
-	addr = atoi(argv[1]);
+	if (argc > 2)
+	    len = atoi(argv[2]);
+	else
+	    len = 16;
 
 	for (int i = 0; i < 16; i += 2) {
 	    uint16_t data;
@@ -99,6 +175,19 @@
 		flashwriteword(data);
 	}
 	flashstopwrite();
+    } else if (!strcmp(argv[0], "tw")) {
+	/* Copy default to RAM */
+	bcopy(&default_settings, &ram_settings, sizeof(default_settings));
+	
+	/* Write RAM copy into flash */
+	flashwriteblock(0, sizeof(ram_settings), &ram_settings);
+    } else if (!strcmp(argv[0], "tr")) {
+	int crcok;
+	
+	/* Read flash copy to RAM */
+	crcok = flashreadblock(0, sizeof(ram_settings), &ram_settings);
+	
+	printf("CRC is %s\r\n", crcok ? "OK" : "bad");
     } else if (!strcmp(argv[0], "id")) {
 	printf("Flash ID = 0x%04hx (expect 0xbf41)\r\n", flashreadid());
     } else {
@@ -120,6 +209,7 @@
   
     FL_DESELECT();
     
+    //fputs("4k erase ", stdout);
     flashwait();
 }
 
@@ -210,6 +300,7 @@
 
 void
 flashwrite(uint32_t addr, uint8_t data) {
+    flashwait();
     flashenablewrite();			/* Enable writes */
 
     FL_SELECT();			/* Select device */
@@ -295,6 +386,7 @@
 flashwriteword(uint16_t data) {
     assert(writestate == RW_RUNNING);
     
+    //fputs("write word ", stdout);
     flashwait();			/* Wait until not busy */
 
     FL_SELECT();			/* Select device */
@@ -310,6 +402,7 @@
 flashstopwrite(void) {
     assert(writestate == RW_RUNNING);
 
+    //fputs("flash stop write start ", stdout);
     flashwait();			/* Wait until not busy */
 
     FL_SELECT();			/* Select device */
@@ -318,8 +411,85 @@
 
     FL_DESELECT();			/* Deselect device */
 
+    //fputs("flash stop write end ", stdout);
     flashwait();			/* Wait until not busy */
 
     writestate = RW_IDLE;
 }
 
+int
+flashreadblock(uint32_t addr, uint32_t len, void *_data) {
+    uint8_t	*data = _data;
+    uint32_t	flashcrc, ramcrc;
+
+    /* Must be a multiple of 4 due to CRC check */
+    assert(len % 4 == 0);
+
+    flashstartread(addr);
+    for (int i = len; i > 0; i--) {
+	*data = flashreadbyte();
+	data++;
+    }
+
+    flashcrc = flashreadbyte();
+    flashcrc |= flashreadbyte() << 8;
+    flashcrc |= flashreadbyte() << 16;
+    flashcrc |= flashreadbyte() << 24;
+
+    flashstopread();
+
+   /* Calculate CRC */
+   CRC_ResetDR();
+   ramcrc = CRC_CalcBlockCRC((uint32_t *)_data, len / 4);
+
+   printf("RAM CRC 0x%08x Flash CRC 0x%08x\r\n", (uint)ramcrc, (uint)flashcrc);
+   
+   if (ramcrc == flashcrc)
+       return 1;
+   else
+       return 0;
+}
+
+void
+flashwriteblock(uint32_t addr, uint32_t len, void *_data) {
+    uint16_t	*data = _data;
+    uint32_t	crc;
+    
+    printf("Writing %u bytes to 0x%06x\r\n", (uint)len, (uint)addr);
+    
+    /* Ensure data is
+     * - 16 bit aligned
+     * - a multiple of 32 bits in length (for CRCs, the flash only need 16 bits)
+     * - not longer than a sector 
+     */
+    assert(addr % 2 == 0);
+    assert(len % 4 == 0);
+    assert(len <= 4096);
+    
+    /* Disable write protect */
+    flashwritestatus(0x00);
+
+    /* Erase sector */
+    flash4kerase(addr);
+ 
+    /* Write data */
+   for (uint i = 0; i < len / 2; i++) {
+	if (i == 0)
+	    flashstartwrite(addr, *data);
+	else
+	    flashwriteword(*data);
+	data++;
+    }
+
+   /* Calculate CRC */
+   CRC_ResetDR();
+   crc = CRC_CalcBlockCRC((uint32_t *)_data, len / 4);
+	
+   printf("CRC is 0x%08x\r\n", (uint)crc);
+   
+   /* Write CRC */
+   flashwriteword(crc);
+   flashwriteword(crc >> 16);
+   
+   flashstopwrite();
+}
--- a/flash.h	Sat Nov 17 18:03:48 2012 +1030
+++ b/flash.h	Tue Nov 20 21:54:06 2012 +1030
@@ -8,6 +8,8 @@
 void		flashenablewrite(void);
 void		flashwrite(uint32_t addr, uint8_t data);
 void		flashwait(void);
+int		flashreadblock(uint32_t addr, uint32_t len, void *_data);
+void		flashwriteblock(uint32_t addr, uint32_t len, void *_data);
 
 /* Streaming read/write */
 void		flashstartread(uint32_t addr);
--- a/hw.c	Sat Nov 17 18:03:48 2012 +1030
+++ b/hw.c	Tue Nov 20 21:54:06 2012 +1030
@@ -43,7 +43,7 @@
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOB | 
 			   RCC_APB2Periph_GPIOE | RCC_APB2Periph_SPI1, ENABLE);
 
-    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
+    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC | RCC_AHBPeriph_CRC, ENABLE);
 
     /* Allow access to BKP Domain */
     PWR_BackupAccessCmd(ENABLE);