F439_CPP_SPI_RA8875_TFT_LCD_04 1.0
STM32F439 SPI RA8875 7-inch TFT display with FRAM-backed touch calibration, built on the STM32_GFX, STM32_RA8875 and STM32_MB85RS64V libraries
Loading...
Searching...
No Matches
MB85RS64V.cpp
1/*
2 * MB85RS64V.cpp
3 *
4 * STM32 HAL driver for the Fujitsu (RAMXEED) MB85RS64V SPI FRAM.
5 * See MB85RS64V.hpp for the class documentation.
6 *
7 * Created on: Oct 3, 2026
8 * Author: johng
9 */
10
11#include "MB85RS64V.hpp"
12
25MB85RS64V::MB85RS64V(SPI_HandleTypeDef *hspi, GPIO_TypeDef *csPort, uint16_t csPin, uint32_t timeoutMs,
26 uint8_t maxAttempts)
27 : _spi(hspi), _csPort(csPort), _csPin(csPin), _timeoutMs(timeoutMs),
28 _maxAttempts(maxAttempts == 0 ? 1 : maxAttempts) {
29}
30
34void MB85RS64V::csLow() {
35 HAL_GPIO_WritePin(_csPort, _csPin, GPIO_PIN_RESET);
36}
37
41void MB85RS64V::csHigh() {
42 HAL_GPIO_WritePin(_csPort, _csPin, GPIO_PIN_SET);
43}
44
50bool MB85RS64V::spiConfigOk() const {
51 const SPI_InitTypeDef &i = _spi->Init;
52 const bool mode0 = (i.CLKPolarity == SPI_POLARITY_LOW) && (i.CLKPhase == SPI_PHASE_1EDGE);
53 const bool mode3 = (i.CLKPolarity == SPI_POLARITY_HIGH) && (i.CLKPhase == SPI_PHASE_2EDGE);
54 return i.Mode == SPI_MODE_MASTER && i.Direction == SPI_DIRECTION_2LINES
55 && i.DataSize == SPI_DATASIZE_8BIT && i.FirstBit == SPI_FIRSTBIT_MSB
56 && i.NSS == SPI_NSS_SOFT && (mode0 || mode3);
57}
58
66bool MB85RS64V::isTransient(HAL_StatusTypeDef status) const {
67 if (status == HAL_BUSY || status == HAL_TIMEOUT) {
68 return true;
69 }
70 if (status != HAL_ERROR) {
71 return false;
72 }
73 // HAL_ERROR is also returned for a bad parameter or state, which a retry cannot fix; only the
74 // SPI error codes that describe a problem during the transfer itself count as transient.
75 uint32_t transfer = 0;
76#ifdef HAL_SPI_ERROR_MODF
77 transfer |= HAL_SPI_ERROR_MODF;
78#endif
79#ifdef HAL_SPI_ERROR_CRC
80 transfer |= HAL_SPI_ERROR_CRC;
81#endif
82#ifdef HAL_SPI_ERROR_OVR
83 transfer |= HAL_SPI_ERROR_OVR;
84#endif
85#ifdef HAL_SPI_ERROR_FRE
86 transfer |= HAL_SPI_ERROR_FRE;
87#endif
88#ifdef HAL_SPI_ERROR_DMA
89 transfer |= HAL_SPI_ERROR_DMA;
90#endif
91#ifdef HAL_SPI_ERROR_FLAG
92 transfer |= HAL_SPI_ERROR_FLAG;
93#endif
94 return (HAL_SPI_GetError(_spi) & transfer) != 0;
95}
96
104bool MB85RS64V::transmit(const uint8_t *data, uint16_t length) {
105 // HAL takes a non-const pointer for historical reasons but does not modify a transmit buffer.
106 _lastStatus = HAL_SPI_Transmit(_spi, const_cast<uint8_t *>(data), length, _timeoutMs);
107 _lastRetryable = (_lastStatus != HAL_OK) && isTransient(_lastStatus);
108 return _lastStatus == HAL_OK;
109}
110
118bool MB85RS64V::receive(uint8_t *data, uint16_t length) {
119 _lastStatus = HAL_SPI_Receive(_spi, data, length, _timeoutMs);
120 _lastRetryable = (_lastStatus != HAL_OK) && isTransient(_lastStatus);
121 return _lastStatus == HAL_OK;
122}
123
129bool MB85RS64V::sendCommand(uint8_t opcode) {
130 return run([&]() {
131 csLow();
132 const bool ok = transmit(&opcode, 1);
133 csHigh();
134 return ok;
135 });
136}
137
146 csHigh();
147 if (!spiConfigOk()) {
148 return false;
149 }
150 uint8_t id[ID_LENGTH];
151 if (!readId(id)) {
152 return false;
153 }
154 if (id[0] != 0x04 || id[1] != 0x7F || id[2] != 0x03 || id[3] != 0x02) {
155 return false;
156 }
157 return writeDisable();
158}
159
166bool MB85RS64V::readId(uint8_t *id) {
167 if (id == nullptr) {
168 return false;
169 }
170 const uint8_t op = OP_RDID;
171 return run([&]() {
172 csLow();
173 const bool ok = transmit(&op, 1) && receive(id, ID_LENGTH);
174 csHigh();
175 return ok;
176 });
177}
178
186bool MB85RS64V::read(uint16_t address, uint8_t *buffer, size_t length) {
187 if (buffer == nullptr || length == 0 || address >= SIZE_BYTES || length > static_cast<size_t>(SIZE_BYTES - address)) {
188 return false;
189 }
190 const uint8_t header[3] = { OP_READ, static_cast<uint8_t>(address >> 8), static_cast<uint8_t>(address & 0xFF) };
191 return run([&]() {
192 csLow();
193 const bool ok = transmit(header, sizeof(header)) && receive(buffer, static_cast<uint16_t>(length));
194 csHigh();
195 return ok;
196 });
197}
198
210bool MB85RS64V::write(uint16_t address, const uint8_t *data, size_t length) {
211 if (data == nullptr || length == 0 || address >= SIZE_BYTES || length > static_cast<size_t>(SIZE_BYTES - address)) {
212 return false;
213 }
214 const uint8_t header[3] = { OP_WRITE, static_cast<uint8_t>(address >> 8), static_cast<uint8_t>(address & 0xFF) };
215 // Write enable and write are retried together: the enable latch clears after a write ends
216 return run([&]() {
217 uint8_t wren = OP_WREN;
218 csLow();
219 bool ok = transmit(&wren, 1);
220 csHigh();
221 if (!ok) {
222 return false;
223 }
224 csLow();
225 ok = transmit(header, sizeof(header)) && transmit(data, static_cast<uint16_t>(length));
226 csHigh();
227 return ok;
228 });
229}
230
236 return sendCommand(OP_WREN);
237}
238
244 return sendCommand(OP_WRDI);
245}
246
252bool MB85RS64V::readStatus(uint8_t *status) {
253 if (status == nullptr) {
254 return false;
255 }
256 const uint8_t op = OP_RDSR;
257 return run([&]() {
258 csLow();
259 const bool ok = transmit(&op, 1) && receive(status, 1);
260 csHigh();
261 return ok;
262 });
263}
264
271bool MB85RS64V::writeStatus(uint8_t status) {
272 const uint8_t frame[2] = { OP_WRSR, status };
273 return run([&]() {
274 uint8_t wren = OP_WREN;
275 csLow();
276 bool ok = transmit(&wren, 1);
277 csHigh();
278 if (!ok) {
279 return false;
280 }
281 csLow();
282 ok = transmit(frame, sizeof(frame));
283 csHigh();
284 return ok;
285 });
286}
287
295 uint8_t status;
296 if (!readStatus(&status)) {
297 return false;
298 }
299 status = static_cast<uint8_t>((status & ~(STATUS_BP1 | STATUS_BP0)) | static_cast<uint8_t>(area));
300 return writeStatus(status);
301}
bool writeDisable()
Clears the write enable latch (WRDI, 04h).
bool writeStatus(uint8_t status)
Writes the status register (WREN, then WRSR, 01h); a retry repeats both steps.
bool read(uint16_t address, uint8_t *buffer, size_t length)
Reads bytes from the FRAM array (READ, 03h).
BlockProtect
Areas of the array that the block-protect bits can lock against writes.
Definition MB85RS64V.hpp:95
static constexpr uint16_t SIZE_BYTES
Capacity in bytes (8192; addresses 0x0000 to 0x1FFF).
Definition MB85RS64V.hpp:81
static constexpr size_t ID_LENGTH
Number of bytes returned by readId().
Definition MB85RS64V.hpp:84
bool readStatus(uint8_t *status)
Reads the status register (RDSR, 05h).
bool setBlockProtect(BlockProtect area)
Sets which part of the array the block-protect bits lock against writes, keeping the other writable s...
bool write(uint16_t address, const uint8_t *data, size_t length)
Writes bytes to the FRAM array (WREN, then WRITE, 02h); a retry repeats both steps.
static constexpr uint8_t STATUS_BP1
Block protect bit 1.
Definition MB85RS64V.hpp:90
bool begin()
Checks the SPI setup and the chip's identity, and leaves writes disabled.
MB85RS64V(SPI_HandleTypeDef *hspi, GPIO_TypeDef *csPort, uint16_t csPin, uint32_t timeoutMs=100, uint8_t maxAttempts=3)
Creates the driver object; does not touch the hardware (call begin() for that).
Definition MB85RS64V.cpp:25
bool writeEnable()
Sets the write enable latch (WREN, 06h). Normally not needed; write() does it.
static constexpr uint8_t STATUS_BP0
Block protect bit 0.
Definition MB85RS64V.hpp:89
bool readId(uint8_t *id)
Reads the four-byte device ID (RDID, 9Fh).