|
3 | 3 | * Copyright (c) 2014 by Paul Stoffregen <[email protected]> (Transaction API)
|
4 | 4 | * Copyright (c) 2014 by Matthijs Kooijman <[email protected]> (SPISettings AVR)
|
5 | 5 | * Copyright (c) 2014 by Andrew J. Kroll <[email protected]> (atomicity fixes)
|
| 6 | + * Copyright (c) 2024 by Mitchell C. Nelson, PhD <[email protected]> |
6 | 7 | * SPI Master library for arduino.
|
7 | 8 | *
|
8 | 9 | * This file is free software; you can redistribute it and/or modify
|
9 | 10 | * it under the terms of either the GNU General Public License version 2
|
10 | 11 | * or the GNU Lesser General Public License version 2.1, both as
|
11 | 12 | * published by the Free Software Foundation.
|
| 13 | + * |
| 14 | + * |
12 | 15 | */
|
13 | 16 |
|
14 | 17 | /**************************************************************************************
|
@@ -203,7 +206,102 @@ uint8_t ArduinoSPI::transfer(uint8_t data)
|
203 | 206 | return rxbuf;
|
204 | 207 | }
|
205 | 208 |
|
| 209 | +/* This provides true 16 bit transfers |
| 210 | + */ |
206 | 211 | uint16_t ArduinoSPI::transfer16(uint16_t data)
|
| 212 | +{ |
| 213 | + uint16_t rxbuf; |
| 214 | + |
| 215 | + if (_is_sci) { |
| 216 | + _spi_cb_event[_cb_event_idx] = SPI_EVENT_TRANSFER_ABORTED; |
| 217 | + |
| 218 | + _write_then_read(&_spi_sci_ctrl, &data, &rxbuf, 1, SPI_BIT_WIDTH_16_BITS); |
| 219 | + |
| 220 | + for (auto const start = millis(); |
| 221 | + (SPI_EVENT_TRANSFER_COMPLETE != _spi_cb_event[_cb_event_idx]) && (millis() - start < 1000); ) |
| 222 | + { |
| 223 | + __NOP(); |
| 224 | + } |
| 225 | + if (SPI_EVENT_TRANSFER_ABORTED == _spi_cb_event[_cb_event_idx]) |
| 226 | + { |
| 227 | + end(); |
| 228 | + return 0; |
| 229 | + } |
| 230 | + } |
| 231 | + else |
| 232 | + { |
| 233 | + _spi_ctrl.p_regs->SPCR_b.SPE = 0; /* disable SPI unit */ |
| 234 | + _spi_ctrl.p_regs->SPDCR = R_SPI0_SPDCR_SPLW_Msk; /* SPI word access */ |
| 235 | + _spi_ctrl.p_regs->SPCMD_b[0].SPB = 0x0F; /* spi bit width = 16 */ |
| 236 | + _spi_ctrl.p_regs->SPCR_b.SPE = 1; /* enable SPI unit */ |
| 237 | + |
| 238 | + while (!_spi_ctrl.p_regs->SPSR_b.SPTEF){} |
| 239 | + |
| 240 | + _spi_ctrl.p_regs->SPDR = data; |
| 241 | + |
| 242 | + while (!_spi_ctrl.p_regs->SPSR_b.SPRF){} |
| 243 | + |
| 244 | + rxbuf = _spi_ctrl.p_regs->SPDR; |
| 245 | + |
| 246 | + |
| 247 | + _spi_ctrl.p_regs->SPCR_b.SPE = 0; /* disable SPI unit */ |
| 248 | + _spi_ctrl.p_regs->SPDCR = R_SPI0_SPDCR_SPBYT_Msk; /* SPI byte access */ |
| 249 | + _spi_ctrl.p_regs->SPCMD_b[0].SPB = 7; /* spi bit width = 8 */ |
| 250 | + _spi_ctrl.p_regs->SPCR_b.SPE = 1; /* enable SPI unit */ |
| 251 | + } |
| 252 | + |
| 253 | + return rxbuf; |
| 254 | +} |
| 255 | + |
| 256 | +/* Use these three functions when you need to loop over a device |
| 257 | + such as an ADC or DAC where you need to pulse a pin between |
| 258 | + each access. Call transfer16_setup() before the loop, then |
| 259 | + call tansfer16_transfer() inside the loop, and then when you |
| 260 | + are done you may choose to call transfer16_cleanup() to restore |
| 261 | + the default 8 bit setup. |
| 262 | +*/ |
| 263 | + |
| 264 | +uint16_t ArduinoSPI::transfer16_setup() |
| 265 | +{ |
| 266 | + if (!_is_sci) { |
| 267 | + _spi_ctrl.p_regs->SPCR_b.SPE = 0; /* disable SPI unit */ |
| 268 | + _spi_ctrl.p_regs->SPDCR = R_SPI0_SPDCR_SPLW_Msk; /* SPI word access */ |
| 269 | + _spi_ctrl.p_regs->SPCMD_b[0].SPB = 0x0F; /* spi bit width = 16 */ |
| 270 | + _spi_ctrl.p_regs->SPCR_b.SPE = 1; /* enable SPI unit */ |
| 271 | + } |
| 272 | +} |
| 273 | + |
| 274 | +uint16_t ArduinoSPI::transfer16_transfer(uint16_t data) |
| 275 | +{ |
| 276 | + uint16_t rxbuf; |
| 277 | + if (_is_sci) { |
| 278 | + return transfer16(data); |
| 279 | + } |
| 280 | + else { |
| 281 | + while (!_spi_ctrl.p_regs->SPSR_b.SPTEF){} |
| 282 | + |
| 283 | + _spi_ctrl.p_regs->SPDR = data; |
| 284 | + |
| 285 | + while (!_spi_ctrl.p_regs->SPSR_b.SPRF){} |
| 286 | + |
| 287 | + rxbuf = _spi_ctrl.p_regs->SPDR; |
| 288 | + } |
| 289 | +} |
| 290 | + |
| 291 | +uint16_t ArduinoSPI::transfer16_cleanup() |
| 292 | +{ |
| 293 | + _spi_ctrl.p_regs->SPCR_b.SPE = 0; /* disable SPI unit */ |
| 294 | + _spi_ctrl.p_regs->SPDCR = R_SPI0_SPDCR_SPBYT_Msk; /* SPI byte access */ |
| 295 | + _spi_ctrl.p_regs->SPCMD_b[0].SPB = 7; /* spi bit width = 8 */ |
| 296 | + _spi_ctrl.p_regs->SPCR_b.SPE = 1; /* enable SPI unit */ |
| 297 | +} |
| 298 | + |
| 299 | + |
| 300 | +/* This is the original 16 bit transfer as two bytes, with an |
| 301 | + extra 1.4 usecs between the two bytes. |
| 302 | + */ |
| 303 | + |
| 304 | +uint16_t ArduinoSPI::transfer16_asbytes(uint16_t data) |
207 | 305 | {
|
208 | 306 | union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } t;
|
209 | 307 | t.val = data;
|
|
0 commit comments