weAut_01 / weAutSys    R 2.2.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines
Files | Defines | Functions | Variables
Basic I/O drivers (SPI)
+ + Low level system services + +

Overview

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 Documentation

#define nicIsSelected ( )

The Ethernet driver is chip-selected.

This evaluates to true if the ENB28J60's / NIC's chip select is active.

See also:
selectEtherChip
#define memCardIsSelected ( )

The memory card (inserted) is chip-selected.

This evaluates to true if the memory card chip select is active.

See also:
selectMemCard
#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.

See also:
SPI10MHz
#define SPI2MHz

UBRR value to set SPI clock to 2 MHz.

See also:
SPI10MHz
#define SPI1MHz

control value to set SPI 2 clock to 1 MHz

See also:
SPI10MHz
#define SPI400kHz

control value to set SPI 2 clock to 400 kHz

See also:
SPI10MHz
#define SPI200kHz

control value to set SPI 2 clock to 200 kHz

See also:
SPI10MHz
#define SPI100kHz

control value to set SPI 2 clock to 100 kHz

See also:
SPI10MHz
#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.

Parameters:
condconditional expression: true if ready to proceed
errerror 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
retreturn value / expression for return statement in error case; leave blank for use within void functions

Function Documentation

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.

Note:
If the SPI is set for the highest transfer rate this function should never wait (long) for ready if a tiny bit of useful work is done between start send/receive and this call. At high transfer rates this approach is far cheaper — and quicker — than utilising the SPI ready interrupt.
Returns:
the first status reading; can be checked for "was waiting" and for past collisions
See also:
deSelectSPI1_impl
void deSelectSPI1_impl ( void  )

De-select all SPI1 devices (raw)

This function does so without any checks or waits.

See also:
deSelectSPI1()
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.

See also:
deSelectSPI1()
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.

See also:
selectDIdisplayLEDs()
void selectDOdriver ( void  )

Chip-select a SPI 1 device: the digital output driver (DO)

See also:
selectDIdisplayLEDs()
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.

Note:
If the SPI is set for a high transfer rate this function should never wait long for ready if a tiny bit of useful work is done between the start of send/receive and this call. At high transfer rates this "do something and than wait a bit" approach is far cheaper — and quicker — than utilising a SPI ready interrupt.
See also:
deSelectSPI2_impl()
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.

See also:
deSelectSPI2()
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.

See also:
deSelectSPI2()
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.

Parameters:
sendBthe byte to be sent
See also:
spi2Receive
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.

Note:
If said precondition is not met the wait will time out and this function will set the appropriate error bits and return 0.
See also:
spi2Transmit
spi2Tranceive
spi2Tranceive2
Returns:
the byte read from SPI (0 may but must not indicate an error
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.

Parameters:
sendBthe byte to be sent
Returns:
the byte read from SPI (0 may but must not indicate an error)
See also:
spi2Transmit
spi2Receive
spi2Tranceive2
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.

Parameters:
sendB1the byte to be sent first
sendB2the second byte to be sent
Returns:
the byte read from SPI while transmitting sendB2 (0 may but must not indicate an error)
See also:
spi2Transmit
spi2Receive
spi2Tranceive
spi2TranceiveN
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.

Parameters:
sendBthe byte to be sent n times
nnumber to repeat sendB (0 is taken as 1)
Returns:
the byte read from SPI while transmitting sendB2 (0 may but must not indicate an error)
See also:
spi2Transmit
spi2Receive
spi2Tranceive
spi2Tranceive2
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.

Parameters:
receiveBpointer to the buffer to receive n bytes to (must not be NULL if n != 0)
skipif > 0 skip bytes are received and forgotten before receiveB will be filled
nnumber 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.

Parameters:
receiveBpointer to the buffer to receive n bytes to (must not be NULL if n != 0)
nnumber of bytes to be received and filled into receiveB
skipif > 0 skip bytes are received and forgotten after filling n bytes into receiveB

Variable Documentation

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

See also:
SPI5MHz
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).

See also:
SPI50MHz
SPI400kHz
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.