summaryrefslogtreecommitdiff
blob: dcd7299570c50628e51f9abb0733a2e0b5e0373f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
From b079cd09bc942b4a489cad29524418441a44fc82 Mon Sep 17 00:00:00 2001
From: Yann Sionneau <ysionneau@kalray.eu>
Date: Wed, 28 Apr 2021 14:16:01 +0200
Subject: [PATCH 01/15] Follow bootloader protocol for page-by-page erase over
 I2C

For I2C the protocol is slighly different than for USART,
requiring a checksum after the number of pages.

https://sourceforge.net/p/stm32flash/tickets/98/

Signed-off-by: Yann Sionneau <ysionneau@kalray.eu>
[Tormod: Add port flag, no wait, amend messages]
Signed-off-by: Tormod Volden <debian.tormod@gmail.com>
---
 i2c.c   |  2 +-
 port.h  |  1 +
 stm32.c | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/i2c.c b/i2c.c
index bb99545..8425b41 100644
--- a/i2c.c
+++ b/i2c.c
@@ -204,7 +204,7 @@ static port_err_t i2c_flush(struct port_interface __unused *port)
 
 struct port_interface port_i2c = {
 	.name	= "i2c",
-	.flags	= PORT_STRETCH_W,
+	.flags	= PORT_STRETCH_W | PORT_NPAG_CSUM,
 	.open	= i2c_open,
 	.close	= i2c_close,
 	.flush  = i2c_flush,
diff --git a/port.h b/port.h
index 4e728d7..1a28dc6 100644
--- a/port.h
+++ b/port.h
@@ -34,6 +34,7 @@ typedef enum {
 #define PORT_CMD_INIT	(1 << 2)	/* use INIT cmd to autodetect speed */
 #define PORT_RETRY	(1 << 3)	/* allowed read() retry after timeout */
 #define PORT_STRETCH_W	(1 << 4)	/* warning for no-stretching commands */
+#define PORT_NPAG_CSUM	(1 << 5)	/* checksum after number of pages to erase */
 
 /* all options and flags used to open and configure an interface */
 struct port_options {
diff --git a/stm32.c b/stm32.c
index 966048b..82fa26a 100644
--- a/stm32.c
+++ b/stm32.c
@@ -843,6 +843,25 @@ static stm32_err_t stm32_pages_erase(const stm32_t *stm, uint32_t spage, uint32_
 
 		buf[i++] = pages - 1;
 		cs ^= (pages-1);
+		/* For I2C send a checksum after the number of pages (AN4221) */
+		if (port->flags && PORT_NPAG_CSUM) {
+			buf[i++] = cs;
+			p_err = port->write(port, buf, i);
+			if (p_err != PORT_ERR_OK) {
+				fprintf(stderr, "Erase failed sending number of pages.");
+				free(buf);
+				return STM32_ERR_UNKNOWN;
+			}
+			s_err = stm32_get_ack(stm);
+			if (s_err != STM32_ERR_OK) {
+				fprintf(stderr, "Erase failed, no ack after number of pages.");
+				free(buf);
+				return STM32_ERR_UNKNOWN;
+			}
+			cs = 0;
+			i = 0;
+		}
+
 		for (pg_num = spage; pg_num < (pages + spage); pg_num++) {
 			buf[i++] = pg_num;
 			cs ^= pg_num;
@@ -876,6 +895,24 @@ static stm32_err_t stm32_pages_erase(const stm32_t *stm, uint32_t spage, uint32_
 	buf[i++] = pg_byte;
 	cs ^= pg_byte;
 
+	if (port->flags & PORT_NPAG_CSUM) {
+		buf[i++] = cs;
+		p_err = port->write(port, buf, i);
+		if (p_err != PORT_ERR_OK) {
+			fprintf(stderr, "Extended erase failed sending number of pages.");
+			free(buf);
+			return STM32_ERR_UNKNOWN;
+		}
+		s_err = stm32_get_ack(stm);
+		if (s_err != STM32_ERR_OK) {
+			fprintf(stderr, "Extended erase failed, no ack after number of pages.");
+			free(buf);
+			return STM32_ERR_UNKNOWN;
+		}
+		cs = 0;
+		i = 0;
+	}
+
 	for (pg_num = spage; pg_num < spage + pages; pg_num++) {
 		pg_byte = pg_num >> 8;
 		cs ^= pg_byte;
-- 
2.33.0.309.g3052b89438-goog