Skip to content

Commit 784e023

Browse files
committed
drivers/memory: Add SPI flash driver, written in C.
1 parent bdcca42 commit 784e023

File tree

2 files changed

+242
-0
lines changed

2 files changed

+242
-0
lines changed

drivers/memory/spiflash.c

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2016-2017 Damien P. George
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <stdio.h>
28+
#include <string.h>
29+
30+
#include "py/mperrno.h"
31+
#include "py/mphal.h"
32+
#include "extmod/machine_spi.h"
33+
#include "drivers/memory/spiflash.h"
34+
35+
#define CMD_WRITE (0x02)
36+
#define CMD_READ (0x03)
37+
#define CMD_WRDI (0x04)
38+
#define CMD_RDSR (0x05)
39+
#define CMD_WREN (0x06)
40+
#define CMD_SEC_ERASE (0x20)
41+
#define WAIT_SR_TIMEOUT (1000000)
42+
43+
#define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer
44+
#define SECTOR_SIZE (4096) // size of erase sector
45+
46+
// Note: this code is not reentrant with this shared buffer
47+
STATIC uint8_t buf[SECTOR_SIZE];
48+
49+
void mp_spiflash_init(mp_spiflash_t *self) {
50+
mp_hal_pin_write(self->cs, 1);
51+
mp_hal_pin_output(self->cs);
52+
mp_hal_pin_write(self->spi.sck, 0);
53+
mp_hal_pin_output(self->spi.sck);
54+
mp_hal_pin_output(self->spi.mosi);
55+
mp_hal_pin_input(self->spi.miso);
56+
}
57+
58+
STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) {
59+
// can be used for actions needed to acquire bus
60+
(void)self;
61+
}
62+
63+
STATIC void mp_spiflash_release_bus(mp_spiflash_t *self) {
64+
// can be used for actions needed to release bus
65+
(void)self;
66+
}
67+
68+
STATIC void mp_spiflash_transfer(mp_spiflash_t *self, size_t len, const uint8_t *src, uint8_t *dest) {
69+
mp_machine_soft_spi_transfer(&self->spi.base, len, src, dest);
70+
}
71+
72+
STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) {
73+
uint8_t cmd[1] = {CMD_RDSR};
74+
mp_hal_pin_write(self->cs, 0);
75+
mp_spiflash_transfer(self, 1, cmd, NULL);
76+
for (; timeout; --timeout) {
77+
mp_spiflash_transfer(self, 1, cmd, cmd);
78+
if ((cmd[0] & mask) == val) {
79+
break;
80+
}
81+
}
82+
mp_hal_pin_write(self->cs, 1);
83+
if ((cmd[0] & mask) == val) {
84+
return 0; // success
85+
} else if (timeout == 0) {
86+
return -MP_ETIMEDOUT;
87+
} else {
88+
return -MP_EIO;
89+
}
90+
}
91+
92+
STATIC int mp_spiflash_wait_wel1(mp_spiflash_t *self) {
93+
return mp_spiflash_wait_sr(self, 2, 2, WAIT_SR_TIMEOUT);
94+
}
95+
96+
STATIC int mp_spiflash_wait_wip0(mp_spiflash_t *self) {
97+
return mp_spiflash_wait_sr(self, 1, 0, WAIT_SR_TIMEOUT);
98+
}
99+
100+
STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) {
101+
mp_hal_pin_write(self->cs, 0);
102+
mp_spiflash_transfer(self, 1, &cmd, NULL);
103+
mp_hal_pin_write(self->cs, 1);
104+
}
105+
106+
STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) {
107+
// enable writes
108+
mp_spiflash_write_cmd(self, CMD_WREN);
109+
110+
// wait WEL=1
111+
int ret = mp_spiflash_wait_wel1(self);
112+
if (ret != 0) {
113+
return ret;
114+
}
115+
116+
// erase the sector
117+
mp_hal_pin_write(self->cs, 0);
118+
uint8_t cmd[4] = {CMD_SEC_ERASE, addr >> 16, addr >> 8, addr};
119+
mp_spiflash_transfer(self, 4, cmd, NULL);
120+
mp_hal_pin_write(self->cs, 1);
121+
122+
// wait WIP=0
123+
return mp_spiflash_wait_wip0(self);
124+
}
125+
126+
STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, const uint8_t *src) {
127+
// enable writes
128+
mp_spiflash_write_cmd(self, CMD_WREN);
129+
130+
// wait WEL=1
131+
int ret = mp_spiflash_wait_wel1(self);
132+
if (ret != 0) {
133+
return ret;
134+
}
135+
136+
// write the page
137+
mp_hal_pin_write(self->cs, 0);
138+
uint8_t cmd[4] = {CMD_WRITE, addr >> 16, addr >> 8, addr};
139+
mp_spiflash_transfer(self, 4, cmd, NULL);
140+
mp_spiflash_transfer(self, PAGE_SIZE, src, NULL);
141+
mp_hal_pin_write(self->cs, 1);
142+
143+
// wait WIP=0
144+
return mp_spiflash_wait_wip0(self);
145+
}
146+
147+
void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
148+
mp_spiflash_acquire_bus(self);
149+
uint8_t cmd[4] = {CMD_READ, addr >> 16, addr >> 8, addr};
150+
mp_hal_pin_write(self->cs, 0);
151+
mp_spiflash_transfer(self, 4, cmd, NULL);
152+
mp_spiflash_transfer(self, len, dest, dest);
153+
mp_hal_pin_write(self->cs, 1);
154+
mp_spiflash_release_bus(self);
155+
}
156+
157+
int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) {
158+
// TODO optimise so we don't need to erase multiple times for successive writes to a sector
159+
160+
// align to 4096 sector
161+
uint32_t offset = addr & 0xfff;
162+
addr = (addr >> 12) << 12;
163+
164+
// restriction for now, so we don't need to erase multiple pages
165+
if (offset + len > sizeof(buf)) {
166+
printf("mp_spiflash_write: len is too large\n");
167+
return -MP_EIO;
168+
}
169+
170+
mp_spiflash_acquire_bus(self);
171+
172+
// read sector
173+
uint8_t cmd[4] = {CMD_READ, addr >> 16, addr >> 8, addr};
174+
mp_hal_pin_write(self->cs, 0);
175+
mp_spiflash_transfer(self, 4, cmd, NULL);
176+
mp_spiflash_transfer(self, SECTOR_SIZE, buf, buf);
177+
mp_hal_pin_write(self->cs, 1);
178+
179+
// erase sector
180+
int ret = mp_spiflash_erase_sector(self, addr);
181+
if (ret != 0) {
182+
mp_spiflash_release_bus(self);
183+
return ret;
184+
}
185+
186+
// copy new block into buffer
187+
memcpy(buf + offset, src, len);
188+
189+
// write sector in pages of 256 bytes
190+
for (int i = 0; i < SECTOR_SIZE; i += 256) {
191+
ret = mp_spiflash_write_page(self, addr + i, buf + i);
192+
if (ret != 0) {
193+
mp_spiflash_release_bus(self);
194+
return ret;
195+
}
196+
}
197+
198+
mp_spiflash_release_bus(self);
199+
return 0; // success
200+
}

drivers/memory/spiflash.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2016 Damien P. George
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#ifndef MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H
28+
#define MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H
29+
30+
#include "extmod/machine_spi.h"
31+
32+
typedef struct _mp_spiflash_t {
33+
mp_hal_pin_obj_t cs;
34+
// TODO replace with generic SPI object
35+
mp_machine_soft_spi_obj_t spi;
36+
} mp_spiflash_t;
37+
38+
void mp_spiflash_init(mp_spiflash_t *self);
39+
void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest);
40+
int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src);
41+
42+
#endif // MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H

0 commit comments

Comments
 (0)