weAutSys provides the basic the basic driver functions for the (embedded) periphery attached to one of the two weAut_01 SPI interfaces.
Files | |
file | spi.h |
weAutSys'/weAut_01' system calls and services for the SPI interfaces | |
Defines | |
#define | memCardIsSelected() |
The memory card (inserted) is chip-selected. | |
#define | nicIsSelected() |
The Ethernet driver is chip-selected. | |
#define | SPI100kHz |
control value to set SPI 2 clock to 100 kHz | |
#define | SPI10MHz 0 |
Divisor register for UART as SPI (UBRR) setting for 10 MHz. | |
#define | SPI1MHz |
control value to set SPI 2 clock to 1 MHz | |
#define | SPI200kHz |
control value to set SPI 2 clock to 200 kHz | |
#define | SPI2COND_ERR_RET(cond, err, ret) |
Check a SPI2 condition with timeout. | |
#define | SPI2MHz |
UBRR value to set SPI clock to 2 MHz. | |
#define | SPI400kHz |
control value to set SPI 2 clock to 400 kHz | |
#define | SPI5MHz 1 |
Divisor register for UART as SPI (UBRR)) setting for 5 MHz. | |
#define | UCPHA1 |
UCSR1C register (bit number) | |
Functions | |
uint8_t | deSelectSPI1 (void) __attribute__((always_inline)) |
De-select all SPI1 devices. | |
void | deSelectSPI1_impl (void) __attribute__((always_inline)) |
De-select all SPI1 devices (raw) | |
void | deSelectSPI2 (void) __attribute__((always_inline)) |
De-select all SPI2 devices. | |
void | selectDIdisplayLEDs (void) __attribute__((always_inline)) |
Chip-select a SPI 1 device: the digital input display LEDS (HMI) | |
void | selectDOdrivDIleds (void) __attribute__((always_inline)) |
Chip-select two SPI 1 devices: the DO driver and the DI LEDs (HMI) | |
void | selectDOdriver (void) __attribute__((always_inline)) |
Chip-select a SPI 1 device: the digital output driver (DO) | |
void | selectEtherChip (void) __attribute__((always_inline)) |
Chip-select a SPI 2 device: the Ethernet driver chip. | |
void | selectMemCard (void) __attribute__((always_inline)) |
Chip-select a SPI 2 device: the memory card (holder) | |
uint8_t | spi2Receive (void) __attribute__((always_inline)) |
Receive one byte from SPI 2. | |
void | spi2ReceiveNS (uint8_t *receiveB, uint16_t n, uint8_t skip) |
Receive n bytes to a buffer via SPI 2 with optional skip (afterwards) | |
void | spi2ReceiveSN (uint8_t *receiveB, uint16_t skip, uint16_t n) |
Receive n bytes to a buffer via SPI 2 with optional skip (before) | |
uint8_t | spi2Tranceive (uint8_t sendB) __attribute__((always_inline)) |
Send and receive one byte via SPI 2. | |
uint8_t | spi2Tranceive2 (uint8_t sendB1, uint8_t sendB2) |
Send two bytes and receive one byte via SPI 2. | |
uint8_t | spi2TranceiveN (uint8_t sendB, uint8_t n) |
Send a byte n times and receive one byte via SPI 2. | |
void | spi2Transmit (uint8_t sendB) __attribute__((always_inline)) |
Send one byte over SPI 2. | |
Variables | |
uint8_t | spi2Errors |
Accumulated errors at SPI 2. | |
uint8_t | spi2EtherChipBaud |
The SPI (2) clock frequency used for the Ethernet driver chip. | |
uint8_t | spi2MemCardBaud |
The SPI (2) clock frequency used for the memory card (holder) |
#define nicIsSelected | ( | ) |
The Ethernet driver is chip-selected.
This evaluates to true if the ENB28J60's / NIC's chip select is active.
#define memCardIsSelected | ( | ) |
The memory card (inserted) is chip-selected.
This evaluates to true if the memory card chip select is active.
#define SPI10MHz 0 |
Divisor register for UART as SPI (UBRR) setting for 10 MHz.
This value gives the highest possible (UART as) SPI baud rate, that is CPU clock / 2. That would be 10 MHz on a 20 MHz clocked µController, as for example an ATmega1284 at max. speed. An ATmega 2560 would yield max. 8 MHz with this setting.
In the same sense SPI5MHz gives corresponding results of 5 vs. 4 MHz. SPI2MHz, SPI2MHz, SPI400kHz, SPI200kHz and SPI100kHz on the other hand give their nominal value at both 20 MHz and 16 MHz CPU clock; that is on ref intro_secH "weAut_01", ArduinoMega2560, ArduinoUno and others.
#define SPI5MHz 1 |
Divisor register for UART as SPI (UBRR)) setting for 5 MHz.
This value gives the second highest possible (UART as) SPI baud rate, that is CPU clock / 4. That would be 5 MHz on a 20 MHz clocked µController and 4 MHz with a 16 MHz clock (ATmega1284 at max. speed e.g.). (An ATmega 2560 would yield max. 8 MHz with this setting.
#define SPI2COND_ERR_RET | ( | cond, | |
err, | |||
ret | |||
) |
Check a SPI2 condition with timeout.
This helper macro replaces the endless spin wait for SPI 2 conditions. It may be used without trailing semicolon. Example:
SPI2COND_ERR_RET(UCSR1A & (1<<UDRE1), 0x82, ) // wait with timeout // while ( !( UCSR1A & (1<<UDRE1))); // spin wait empty transmit buffer
Compared to the (endless) while wait the use of this macro does not add to runtime if the condition is met from start.
The maximum waiting time or timeout is 2 * (UBRR1 + 1) * 10 clocks. That is ~20% longer than minimal necessary — but far better than endless waiting leading to watchdog reset.
cond | conditional expression: true if ready to proceed |
err | error bits to be set in spi2Errors in case of waiting for cond times out (by more than The xyzIsSelected bits are set by this macro |
ret | return value / expression for return statement in error case; leave blank for use within void functions |
uint8_t deSelectSPI1 | ( | void | ) |
De-select all SPI1 devices.
This (low level helper) function de-activates the chip selects (sometimes aka slave selects) of all SPI 1 devices. For configurations without SPI1 devices nothing is done.
By polling SPI1's status it is checked before de-selecting if the interface is still busy. If so, it will be waited until ready. With higher transfer rates (CPU clock /2) that won't be long.
Returned is the first reading of the SPI1 status.
void deSelectSPI1_impl | ( | void | ) |
De-select all SPI1 devices (raw)
This function does so without any checks or waits.
void selectDIdisplayLEDs | ( | void | ) |
Chip-select a SPI 1 device: the digital input display LEDS (HMI)
This (low level helper) function activates the chip select of a SPI 1 device and de-selects all others at the same SPI bus. For configurations without that device nothing is done.
This select / de-select is done without any checks or waits.
void selectDOdrivDIleds | ( | void | ) |
Chip-select two SPI 1 devices: the DO driver and the DI LEDs (HMI)
After this "double select" the same value can be output to both devices in one SPI (shift) operation.
So far this is only used for initialising both with 0 by system (start) software.
void selectDOdriver | ( | void | ) |
Chip-select a SPI 1 device: the digital output driver (DO)
void deSelectSPI2 | ( | void | ) |
De-select all SPI2 devices.
This (low level helper) function de-activates the chip selects (sometimes aka slave selects) of all SPI 2 devices. For configurations without such devices nothing is done.
By polling ISP2's status, it is checked before de-selecting, if the interface's transmitter is still busy. If so, it will be waited until ready, i.e. for transmission complete (TXC). If this waiting times out the appropriate error bits are set.
void selectEtherChip | ( | void | ) |
Chip-select a SPI 2 device: the Ethernet driver chip.
This (low level helper) function activates the chip select of a SPI 2 device and de-selects all others at the same SPI bus. For configurations without that device nothing is done.
This select / de-select is done without any checks or waits.
void selectMemCard | ( | void | ) |
Chip-select a SPI 2 device: the memory card (holder)
This (low level helper) function activates the chip select of a SPI 2 device and de-selects all others at the same SPI bus. For configurations without that device nothing is done.
This select / de-select is done without any checks or waits.
void spi2Transmit | ( | uint8_t | sendB | ) |
Send one byte over SPI 2.
This function implies that the SPI device has been selected correctly before. It waits for empty transmit buffer, writes the byte sendB
and clears the transmit complete flag.
If waiting for empty transmit buffer takes too long this function will set the appropriate error bits and does nothing else.
sendB | the byte to be sent |
uint8_t spi2Receive | ( | void | ) |
Receive one byte from SPI 2.
This function implies that at least one byte has been sent over the SPI to trigger or clock the receive shift and the respective byte has not yet been consumed. The function waits for the receive complete flag and than return the byte read by SPI as result.
uint8_t spi2Tranceive | ( | uint8_t | sendB | ) |
Send and receive one byte via SPI 2.
This function implies that the SPI device has been is selected correctly before.
It effectively combines spi2Transmit(sendB) and return spi2Receive() and guarantees the correct pairing of SPI transmit and receive.
On the other hand it does neither allow useful work instead of the second (TXC) wait nor utilise the SPI2 (USAT2 as SPI) double buffering.
sendB | the byte to be sent |
uint8_t spi2Tranceive2 | ( | uint8_t | sendB1, |
uint8_t | sendB2 | ||
) |
Send two bytes and receive one byte via SPI 2.
This function acts as if calling spi2Tranceive twice (returning the second call's result). Compared to that proceeding this function is 20% faster by utilising the SPI2's (USAT2 as SPI) double buffering. The device sees a continuous stream of 16 clocks instead of 2 times 8 clocks with a gap.
sendB1 | the byte to be sent first |
sendB2 | the second byte to be sent |
sendB2
(0 may but must not indicate an error) uint8_t spi2TranceiveN | ( | uint8_t | sendB, |
uint8_t | n | ||
) |
Send a byte n times and receive one byte via SPI 2.
This function sends the byte sendB
one or more times via SPI 2 discarding all receptions except for the last one. Compared to doing this by spi2Tranceive(sendB) n
times (in a loop) this function is at least 20 % faster cause of no gaps in the byte (MoSi) respectively clock (sClk) stream.
On the other hand no useful work or PT_YIELD yielding can be done while the SPI (2) interface is busy with this action. Insofar n
should be reasonably small.
sendB | the byte to be sent n times |
n | number to repeat sendB (0 is taken as 1) |
sendB2
(0 may but must not indicate an error) void spi2ReceiveSN | ( | uint8_t * | receiveB, |
uint16_t | skip, | ||
uint16_t | n | ||
) |
Receive n bytes to a buffer via SPI 2 with optional skip (before)
This function does skip
+ n
receptions via SPI2 (putting all ones on MoSi). The (last) n
bytes received are put into the buffer receiveB
.
Compared to doing this by spi2Tranceive(0xFF) skip
+ n
times this function is at least 20 % faster. On the other hand no useful work or yielding can be done while the SPI (2) interface is busy with the action. Insofar skip
+ n
should be reasonably small.
receiveB | pointer to the buffer to receive n bytes to (must not be NULL if n != 0) |
skip | if > 0 skip bytes are received and forgotten before receiveB will be filled |
n | number of bytes to be received and filled into receiveB |
void spi2ReceiveNS | ( | uint8_t * | receiveB, |
uint16_t | n, | ||
uint8_t | skip | ||
) |
Receive n bytes to a buffer via SPI 2 with optional skip (afterwards)
This function does skip
+ n
receptions via SPI2 (putting all ones on MoSi). The (first) n
bytes received are put into the buffer receiveB
.
Compared to doing this by spi2Tranceive(0xFF) n
+ skip
times this function is at least 20 % faster. On the other hand no useful work or yielding can be done while the SPI (2) interface is busy with the action. Insofar n
+ skip
should be reasonably small.
receiveB | pointer to the buffer to receive n bytes to (must not be NULL if n != 0) |
n | number of bytes to be received and filled into receiveB |
skip | if > 0 skip bytes are received and forgotten after filling n bytes into receiveB |
uint8_t spi2EtherChipBaud |
The SPI (2) clock frequency used for the Ethernet driver chip.
This is the control value used to set the SPI (2) clock frequency (aka baud rate) if used with the Ethernet driver.
Hint 1: For 20 MHz FCPU_S STR "CPU frequency" the SPI (2) frequency can be set in the range 10 MHz (value 0) down to 40 kHz (value 249).
Hint 2: Due to different and un-synchronous clocks for the CPU (20 MHz) and the Ethernet chip (ENC28J60 25 MHz) not all baudrates go well. 2 MHz proofed rock solid reliable and is the default even if 5 or 10 MHz would give more performance.
default / init: SPI2MHz
uint8_t spi2MemCardBaud |
The SPI (2) clock frequency used for the memory card (holder)
This is the control value used to set the SPI (2) clock frequency (aka baud rate) if used with the small memory card.
Hint 1: For 20 MHz FCPU_S STR "CPU frequency" the SPI (2) frequency can be set in the range 10 MHz (value 0) down to 40 kHz (value 249). 5 MHz is the default or reset initialisation value.
Hint 2: Most small memory cards require 400 kHz or slower during initialisation (power up and idle state). This can be done by smcSetIdle(1) no matter the spi2MemCardBaud value After initialisation and depending on the card type information read a higher frequency can and should be set (here).
uint8_t spi2Errors |
Accumulated errors at SPI 2.
Driver function of SPI 2 (UART1 as SPI) record seen errors in this byte. It may be reset by user or system software (especially after logging or displaying the error(s)).software.
Bit 7 (8): any error. This bit will be set on every recognised SPI 2 error. It may be reset alone leaving all others set.
Bit (4)6: any memory card error. This bit will be set on every recognised SPI 2 error if at that time the small memory card holder is selected. Bit 5 (2): any network interface / ENC28J60 error. This bit will be set on every recognised SPI 2 error if at that time the Ethernet chip is selected.
Bit 3 (8): network interface controller (NIC, ENC28J60) stays busy. This bit will be set if waiting for the MISTAT.BUSY bit to go away timed out.
Bit 2 (4): transmit complete failed. This bit will be set if waiting for transmission complete (TXC) timed out.
Bit 1 (2): transmitter buffer empty failed. This bit will be set if waiting for empty transmitter buffer (UDRE) timed out.
Bit 0 (1): receive complete failed. This bit will be set if waiting for receive complete (RXC) timed out.