ACwing FC firmware
STM32WB55: attitude IEKF, altitude Kalman filter, flight core, protocol v2
Loading...
Searching...
No Matches
w25q.c
Go to the documentation of this file.
1
6#include "w25q.h"
7#include <string.h>
8
9#define CMD_WREN 0x06u
10#define CMD_RDSR1 0x05u
11#define CMD_READ 0x03u /* up to 50 MHz; the binding runs below that */
12#define CMD_PP 0x02u
13#define CMD_SE 0x20u /* 4 KB */
14#define CMD_CE 0xC7u
15#define CMD_JEDEC 0x9Fu
16#define CMD_RELEASE_PD 0xABu
17#define SR1_BUSY 0x01u
18#define SR1_WEL 0x02u
19
20#define T_PP_MS 3u /* page program max */
21#define T_SE_MS 400u /* sector erase max */
22#define T_CE_MS 200000u /* chip erase max */
23
24static int cmd1(w25q_t *d, uint8_t c) { return d->bus.xfer(d->bus.ctx, &c, 1, NULL, 0); }
25
26static int status(w25q_t *d, uint8_t *sr)
27{
28 const uint8_t c = CMD_RDSR1;
29 return d->bus.xfer(d->bus.ctx, &c, 1, sr, 1);
30}
31
32/* waits for BUSY = 0; polls fast first (page program), then yields */
33static int wait_ready(w25q_t *d, uint32_t max_ms)
34{
35 const uint32_t t0 = d->bus.now_ms ? d->bus.now_ms() : 0u;
36 for (uint32_t k = 0;; ++k) {
37 uint8_t sr = 0xFFu;
38 if (status(d, &sr) != 0) return -1;
39 if (!(sr & SR1_BUSY)) return 0;
40 if (d->bus.now_ms && (d->bus.now_ms() - t0) > max_ms + 10u) return -2;
41 if (!d->bus.now_ms && k > max_ms * 100u) return -2; /* host / no clock */
42 if (k > 20u && d->bus.delay_ms) d->bus.delay_ms(1);
43 }
44}
45
46static int write_enable(w25q_t *d)
47{
48 if (cmd1(d, CMD_WREN) != 0) return -1;
49 uint8_t sr = 0;
50 if (status(d, &sr) != 0 || !(sr & SR1_WEL)) return -1;
51 return 0;
52}
53
54static void a24(uint8_t *b, uint8_t cmd, uint32_t a)
55{
56 b[0] = cmd; b[1] = (uint8_t)(a >> 16); b[2] = (uint8_t)(a >> 8); b[3] = (uint8_t)a;
57}
58
59int w25q_init(w25q_t *d, const w25q_bus_t *bus)
60{
61 memset(d, 0, sizeof *d);
62 d->bus = *bus;
63 (void)cmd1(d, CMD_RELEASE_PD);
64 if (d->bus.delay_ms) d->bus.delay_ms(1); /* tRES1 = 3 us */
65 uint8_t id[3] = { 0, 0, 0 };
66 const uint8_t c = CMD_JEDEC;
67 if (d->bus.xfer(d->bus.ctx, &c, 1, id, 3) != 0) return -1;
68 d->mfr = id[0]; d->type = id[1]; d->cap = id[2];
69 /* Winbond 0xEF, 0x40 (SPI) / 0x70 (QPI-capable JV-IM); capacity 2^cap bytes */
70 if (d->mfr != 0xEFu || (d->type != 0x40u && d->type != 0x70u) || d->cap < 0x14u || d->cap > 0x18u) return -2;
71 d->size = 1u << d->cap; /* 0x18 = 16 MB: 3-byte addresses */
72 return 0;
73}
74
75int w25q_read(w25q_t *d, uint32_t addr, void *buf, uint32_t n)
76{
77 if (addr + n > d->size) return -1;
78 uint8_t c[4];
79 a24(c, CMD_READ, d->base + addr);
80 return d->bus.xfer(d->bus.ctx, c, 4, (uint8_t *)buf, n);
81}
82
83int w25q_prog(w25q_t *d, uint32_t addr, const void *buf, uint32_t n)
84{
85 if (n == 0u) return 0;
86 if (addr + n > d->size || (addr & 0xFFu) + n > 256u) return -1; /* one page */
87 if (write_enable(d) != 0) return -1;
88 uint8_t c[4];
89 a24(c, CMD_PP, d->base + addr);
90 if (d->bus.xfer_w(d->bus.ctx, c, 4, (const uint8_t *)buf, n) != 0) return -1;
91 return wait_ready(d, T_PP_MS);
92}
93
94int w25q_erase_sector(w25q_t *d, uint32_t addr)
95{
96 if (addr >= d->size || (addr & 0xFFFu)) return -1;
97 if (write_enable(d) != 0) return -1;
98 uint8_t c[4];
99 a24(c, CMD_SE, d->base + addr);
100 if (d->bus.xfer(d->bus.ctx, c, 4, NULL, 0) != 0) return -1;
101 return wait_ready(d, T_SE_MS);
102}
103
105{
106 if (write_enable(d) != 0) return -1;
107 if (cmd1(d, CMD_CE) != 0) return -1;
108 return wait_ready(d, T_CE_MS);
109}
110
111int w25q_lf_read(void *ctx, uint32_t a, void *b, uint32_t n) { return w25q_read((w25q_t *)ctx, a, b, n); }
112int w25q_lf_prog(void *ctx, uint32_t a, const void *b, uint32_t n) { return w25q_prog((w25q_t *)ctx, a, b, n); }
113int w25q_lf_erase(void *ctx, uint32_t a) { return w25q_erase_sector((w25q_t *)ctx, a); }
double b[6]
Definition calib_mgr.c:53
uint32_t n
Definition calib_mgr.c:35
double sr
Definition calib_mgr.c:42
static uint32_t addr(uint16_t sect)
Definition log_store.c:49
static void cmd(uint8_t port, const uint8_t *c, uint32_t n, uint8_t armed, uint32_t now)
Definition log_task.c:222
int(* xfer)(void *ctx, const uint8_t *tx, uint32_t ntx, uint8_t *rx, uint32_t nrx)
CS low, write tx (ntx bytes), read rx (nrx bytes), CS high; 0 = ok.
Definition w25q.h:21
uint32_t(* now_ms)(void)
Definition w25q.h:25
int(* xfer_w)(void *ctx, const uint8_t *tx, uint32_t ntx, const uint8_t *data, uint32_t n)
same, with a second write buffer after tx (page program data)
Definition w25q.h:23
void(* delay_ms)(uint32_t ms)
yields the task while the chip is busy
Definition w25q.h:24
void * ctx
Definition w25q.h:26
Definition w25q.h:29
uint32_t base
start of the log area
Definition w25q.h:33
uint8_t type
Definition w25q.h:32
uint8_t mfr
Definition w25q.h:32
uint8_t cap
JEDEC id
Definition w25q.h:32
uint32_t size
bytes, from the JEDEC id
Definition w25q.h:31
w25q_bus_t bus
Definition w25q.h:30
int w25q_init(w25q_t *d, const w25q_bus_t *bus)
reads the JEDEC id, releases power-down; 0 = a W25Q-compatible part
Definition w25q.c:59
int w25q_lf_erase(void *ctx, uint32_t a)
Definition w25q.c:113
#define T_CE_MS
Definition w25q.c:22
#define CMD_WREN
Definition w25q.c:9
#define CMD_PP
Definition w25q.c:12
static void a24(uint8_t *b, uint8_t cmd, uint32_t a)
Definition w25q.c:54
#define CMD_JEDEC
Definition w25q.c:15
#define T_SE_MS
Definition w25q.c:21
int w25q_lf_read(void *ctx, uint32_t a, void *b, uint32_t n)
Definition w25q.c:111
int w25q_prog(w25q_t *d, uint32_t addr, const void *buf, uint32_t n)
inside one page
Definition w25q.c:83
#define T_PP_MS
Definition w25q.c:20
int w25q_erase_chip(w25q_t *d)
waits (≤ 200 s)
Definition w25q.c:104
int w25q_read(w25q_t *d, uint32_t addr, void *buf, uint32_t n)
Definition w25q.c:75
static int wait_ready(w25q_t *d, uint32_t max_ms)
Definition w25q.c:33
#define CMD_CE
Definition w25q.c:14
static int cmd1(w25q_t *d, uint8_t c)
Definition w25q.c:24
static int write_enable(w25q_t *d)
Definition w25q.c:46
#define CMD_READ
Definition w25q.c:11
int w25q_lf_prog(void *ctx, uint32_t a, const void *b, uint32_t n)
Definition w25q.c:112
#define CMD_RDSR1
Definition w25q.c:10
static int status(w25q_t *d, uint8_t *sr)
Definition w25q.c:26
#define SR1_WEL
Definition w25q.c:18
#define CMD_SE
Definition w25q.c:13
int w25q_erase_sector(w25q_t *d, uint32_t addr)
4 KB, waits (≤ 400 ms)
Definition w25q.c:94
#define SR1_BUSY
Definition w25q.c:17
#define CMD_RELEASE_PD
Definition w25q.c:16
Winbond W25Q serial NOR flash (W25Q128JV on the ACwing FC: 16 MB, 4 KB sectors, 256-byte pages,...