Sign in Join
Wiki copytemporary

AVR Embedded Tutorial - SPI-Slave: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: AVR Embedded Tutorial - SPI-Slave

OldNewLine
1+# SPI as a slave
2+
3+SPI can also be used as a slave. The best way to handle SPI responding to an input is to use interrupt control.
4+
5+The following functions are described in these tutorials:
6+
7+- [[AVR Embedded Tutorial - Simple GPIO on and off output|GPIO - Out / Input]] - How do I make a GPIO access on the AVR.
8+- [[AVR Embedded Tutorial - UART|UART - serial input and output]] - (COM port).
9+- [[AVR Embedded Tutorial - SPI|SPI - use of the hardware SPI interface]].
10+
11+# Atmega328 / Arduino Uno / Nano Example
12+
13+In this example, an interrupt is triggered as soon as a character is present at the input and then this is written to the ring buffer.
14+
15+The main loop checks whether something is in the ring buffer, and if so, this is output via the UART.
16+
17+What you have to watch out for is that you don't get too much in via SPI, since this interface is a few times faster than UART.
18+
19+As a master I used an ATtiny2313, which outputs a string via SPI at the push of a button.
20+
21+At the end there is the code for the ATTiny that sends the strings.
22+
23+## Units
24+
25+Required for SEI.
26+
27+``` pascal
28+ uses
29+ intrinsics;
30+```
31+
32+## Constants and variables
33+
34+Constant and variables for ring buffers.
35+
36+``` pascal
37+ const
38+ // Buffer size
39+ SPI_Buf_Len = 255;
40+
41+ var
42+ // buffer pointer and buffer
43+ SPI_Buf_FirstOut : byte = 0 ;
44+ SPI_Buf_LastIn : byte = 0 ;
45+ SPI_Buf_Data : array[0..SPI_Buf_Len - 1] of byte;
46+```
47+
48+PORTB pins which are required for SPI - only needed if you send something.
49+
50+``` pascal
51+ type
52+ TSPI_GPIO = bitpacked record
53+ p0, p1, SlaveSelect, MOSI, MISO, Clock, p6, p7 : boolean;
54+ end;
55+
56+ var
57+ SPI_Port : TSPI_GPIO absolute PORTB;
58+ SPI_DDR : TSPI_GPIO absolute DDRB;
59+```
60+
61+## Received characters from SPI
62+
63+As soon as the master activates SS, the interrupt is triggered and the incoming character is written to the ring buffer.
64+
65+``` pascal
66+ procedure SPI_Int_Send; public name 'SPI__STC_ISR'; interrupt;
67+ var
68+ tchr : byte;
69+ begin
70+ tchr := SPDR;
71+
72+ if tchr <> 0 then
73+ begin
74+ SPI_Buf_Data[SPI_Buf_LastIn] := tchr;
75+ Inc(SPI_Buf_LastIn);
76+ if SPI_Buf_LastIn >= SPI_Buf_Len then
77+ begin
78+ SPI_Buf_LastIn := 0;
79+ end;
80+ end;
81+ end;
82+```
83+
84+## Main program
85+
86+The main program simply checks whether something is in the ring buffer and as soon as something is there it is output via UART.
87+
88+``` pascal
89+ var
90+ ch : byte;
91+
92+ begin
93+ // initialize UART
94+ UARTInit;
95+
96+ // SPI as slave, interrupt controlled.
97+ SPCR := (1 shl SPE) or (1 shl SPIE);
98+
99+ // activate interrupt
100+ avr_sei ;
101+
102+ // Send Pin
103+ SPI_DDR.MISO := True; // Only necessary if the slave also sends.
104+
105+ repeat
106+ while SPI_Buf_LastIn <> SPI_Buf_FirstOut do // Is there something in the buffer?
107+ begin
108+ ch := SPI_Buf_Data[SPI_Buf_FirstOut];
109+ Inc (SPI_Buf_FirstOut);
110+
111+ if SPI_Buf_FirstOut >= SPI_Buf_Len then
112+ begin
113+ SPI_Buf_FirstOut := 0;
114+ end;
115+
116+ UARTSendChar(char(ch));
117+ end;
118+ until 1 = 2;
119+ end.
120+```
121+
122+# SPI send code for the ATtiny2313
123+
124+This code sends a string as soon as a key is pressed.
125+
126+Since the ATTiny2313 does not have a real SPI, the output is made via the universal interface (USI).
127+
128+There are 3 buttons.
129+
130+``` pascal
131+ program Project1 ;
132+
133+ {$O-}
134+ type
135+ TSPI_GPIO = bitpacked record
136+ p0, p1, p2, p3, SlaveSelect, DataInt, DataOut, Clock : boolean;
137+ end ;
138+
139+ TButton_GPIO = bitpacked array[0..2] of boolean;
140+
141+ var
142+ SPI_PORT : TSPI_GPIO absolute PORTB;
143+ SPI_DDR : TSPI_GPIO absolute DDRB;
144+
145+ Button_PIN : TButton_GPIO absolute PIND;
146+
147+ procedure delay;
148+ var
149+ i : UInt32;
150+ begin
151+ for i := 0 to 65000 do ;
152+ end;
153+
154+ procedure SPIWriteData(p : PByte; len : byte);
155+ var
156+ i : byte;
157+ begin
158+ SPI_PORT.SlaveSelect := False;
159+
160+ for i := 0 to len - 1 do
161+ begin
162+ USIDR := p[i];
163+ USISR := 1 shl USIOIF;
164+
165+ repeat
166+ USICR := (%01 shl USIWM) or (%10 shl USICS) or (1 shl USICLK) or (1 shl USITC);
167+ until (USISR and (1 shl USIOIF)) <> 0;
168+
169+ end;
170+
171+ SPI_PORT.SlaveSelect := True;
172+ end;
173+
174+ const
175+ Text0 = 'Lazarus is great!' + #13#10;
176+ Text1 = 'Hello World !, Hello AVR' + #13#10;
177+ Text2 = 'SPI as slave' + #13#10;
178+
179+ begin
180+ SPI_DDR.DataOut := True;
181+ SPI_DDR.Clock := True;
182+ SPI_DDR.SlaveSelect := True;
183+
184+ repeat
185+ if not Button_PIN[0] then
186+ begin
187+ SPIWriteData(@Text0[1], Length(Text0));
188+ delay;
189+ end;
190+
191+ if not Button_PIN[1] then
192+ begin
193+ SPIWriteData(@Text1[1], Length(Text1));
194+ delay;
195+ end;
196+
197+ if not Button_PIN[2] then
198+ begin
199+ SPIWriteData(@Text2[1], Length(Text2));
200+ delay;
201+ end;
202+ until 1 = 2;
203+ end.
204+```
205+
206+# See also
207+
208+- Overview page - [[AVR Embedded Tutorial]]
209+- [[AVR Embedded Tutorial - Shiftregister|Shift registers]] - How do I control shift registers?
210+- [[AVR Embedded Tutorial - SPI|Use of the hardware SPI interface with an ATmega328 / Arduino]]
211+
212+---
213+*From the Free Pascal wiki, page "AVR Embedded Tutorial - SPI-Slave", as it stood on 2020-03-06 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history