CROSS Technical Documentation User Manual and Technical Doc.
INFN Milano Bicocca
Loading...
Searching...
No Matches
Spi.c
Go to the documentation of this file.
1
2
3#include "tutti_gli_header.h"
4
5// DOCUMENTAZIONE DOXYGEN
6
7/// \file
8
9/// \file SPI_LPC17xx.c
10
11/*! \page SPI_page The SPI bus
12\brief <span style="color:red;"> <b> Spi for relays drivers, ADC and Pga DACS </b> </span>
13
14 \b SUMMARY:
15*\arg \ref user_use_of_SPI
16\arg \ref a_bit_of_SPI_fw
17
18*\section user_use_of_SPI User use of SPI
19<hr width="75%" size="10" align="left">
20
21\n SPI communication follows the same approach adopted for I2C and CAN bus: exploitation of the CMSIS drivers. To this aim there is available a set of functions:
22<span style="color:orange;"> <I>
23\code {.c}
24ARM_DRIVER_SPI Driver_SPI2 = {
25 SPI_GetVersion,
26 SPI_GetCapabilities,
27 SPI_Initialize, //Important for setting the calling function
28 SPI_Uninitialize, //Idle the SPI
29 SPI_PowerControl, //Switch on/off the SPI
30 SPI_Send, //sen data
31 SPI_Receive, //receive data
32 SPI_Transfer,
33 SPI_GetDataCount,
34 SPI_Control,
35 SPI_GetStatus //usefull for polling
36};
37\endcode
38</I> </span>
39
40\n So that an example of their use is the following:
41
42<span style="color:orange;"> <I>
43\code {.c}
44extern ARM_DRIVER_SPI Driver_SPI2; // Viene inclusa la Periferica SPI2
45ARM_DRIVER_SPI *SPIdrv= &Driver_SPI2; // Viene creato un puntatore a Driver_SPI2
46SPIdrv->Control(SPI_control_for_DAC, SPI_DAC_SPEED); // SPI fits DAC specs at 16 bits and speed
47\endcode
48</I> </span>
49
50\n To use the \b SPI first of all we need to intialize it and this is done by SPI_Inizialize() that collects a few functions between those listed above.
51SPI is used by the relay drivers, the ADC and the DAC of the PGA. It is therefore
52set according to them. As an instance, the relay drivers communicate with 8 bits, while the DAC with 16 bits. The core of SPI_Inizialize()
53is the setting of some bits and the clock by calling \b SPIdrv->Control(). The setting bits for \b SPIdrv->Control() are defined at #SPI_control_for_relay_driver
54(the meaning of the bits can be verified at <a href="https://www.keil.com/pack/doc/CMSIS/Driver/html/group__spi__interface__gr.html#gad18d229992598d6677bec250015e5d1a" target=_blank><b>Bits meaning for SPI settings</b></a>)
55with the speed #spi_clock_for_relais, this is the defaul setting.
56\n Every time we manage the realis or the DAC we need to set the SPI accordingly to the parallelism and the speed. For their setting 2 macros are defined:
57#SPI_control_for_DAC with #SPI_DAC_SPEED for the DAC and #SPI_control_for_relay_driver with #spi_clock_for_relais for the relais. An example for their setting is here:
58
59<span style="color:orange;"> <I>
60\code {.c}
61SPIdrv->Control(SPI_control_for_DAC, SPI_DAC_SPEED); // SPI fits DAC specs at 16 bits and speed
62SPIdrv->Control(SPI_control_for_relay_driver, spi_clock_for_relais); // SPI fits Relay driver specs at 8 bits and speed
63\endcode
64</I> </span>
65
66Where #SPI_control_for_relay_driver is:
67\snippet Spi.h ref_SPI_control_for_relay_driver
68
69while #spi_clock_for_relais is:
70\snippet Detector_Relays_managing.h ref_spi_clock_for_relais
71
72\note Pay attention: the SPI clock speed cannot be smaller than 1/255 times the core clock. As an instance, at 100 MHz core clock the
73smaller speed cannot be lower than 400 KHz.
74
75\n Transmission and reception is done with \b SPIdrv->Send() and \b SPIdrv->Receive(), and the polling at \b SPIdrv->GetStatus().busy.
76\b SPIdrv->GetStatus() ia a structue:
77
78\n
79<center>
80\anchor Table_status_fields \b Table \b GetStatus: Fields of the \b SPIdrv->GetStatus().
81<span style="color:red;"> The row highlighted in red is the field we test during communication. </span>
82| Data Fields | | |
83|--------------| :-------: | :-----------------------------------------------------------------------------------------------|
84| uint32_t | <span style="color:red;"> busy: 1 </span> | <span style="color:red;"> Transmitter/Receiver busy flag. </span> |
85| uint32_t | data_lost: 1 | Data lost: Receive overflow / Transmit underflow (cleared on start of transfer operation) |
86| uint32_t | mode_fault: 1 | Mode fault detected; optional (cleared on start of transfer operation) |
87| uint32_t | reserved: 29 | |
88</center>
89
90\n We explooit the field busy, that remains "1" till the SPI operation has concluded.
91\n The SPI_callback() is called after SPI operation has concluded, as a result of the interrupt. If necessary there is available the global
92#evento_SPI which can be alternatively checked in polling, or to verify if a problem has occurred. #evento_SPI
93can take the following values:
94\n
95<center>
96\anchor Table_event \b Table \b Interrupt \b Event: Values that the global #evento_SPI can take.
97<span style="color:red;"> The row highlighted in red is the field we test during communication. </span>
98Parameter event | Bit |Description supported when ARM_SPI_CAPABILITIES
99|:------------------------------| :-------: | :-----------------------------------------------------------------------------------------------|
100<span style="color:red;"> ARM_SPI_EVENT_TRANSFER_COMPLETE </span> | <span style="color:red;"> 1 << 0 </span> | <span style="color:red;"> Occurs after call to ARM_SPI_Send, ARM_SPI_Receive, or ARM_SPI_Transfer <br /> to indicate that all the data has been transferred. The driver is ready for the next transfer operation. </span>
101ARM_SPI_EVENT_DATA_LOST | 1 << 1 | Occurs in slave mode when data is requested/sent by master but send/receive/transfer <br /> operation has not been started and indicates that data is lost. <br /> Occurs also in master mode when driver cannot transfer data fast enough.
102ARM_SPI_EVENT_MODE_FAULT | 1 << 2 | Occurs in master mode when Slave Select is deactivated and indicates Master Mode Fault. <br /> The driver is ready for the next transfer operation.
103</center>
104
105Here an example of use of the polled transmission with DAC:
106<span style="color:orange;"> <I>
107\code {.c}
108DAC_transmission(){
109SPIdrv->Control(SPI_control_for_DAC, SPI_DAC_SPEED); //Set the SPI with 16 bits
110
111//prepare data to send
112uint16_t data_to_send= ...
113SPIdrv->Send ( &data_to_send ,1); //send 1 item at 16 bits
114while( SPIdrv->GetStatus().busy ){} //wait end of transmission
115
116//Function end
117}
118\endcode
119</I> </span>
120
121*\section a_bit_of_SPI_fw A bit more about the fw used for SPI
122<hr width="75%" size="10" align="left">
123
124\n The functions invoked within the fw are the following:
125- SPI_Inizialize() is called at startup to set the SPI;
126- SPI
127
128\n First and only function to be used is the SPI_Inizialize():
129\snippet{lineno} SPI.c fun_SPI_Inizialize
130
131\n
132\n
133
134\sa That shown above is an extraction of the documentation from CMSIS drivers.
135For a complete reference to the SPI driver from CMSIS see the webs at Keil or ARM (in case of failure of either):
136- <a href="https://arm-software.github.io/CMSIS_5/Driver/html/group__spi__interface__gr.html" target=_blank><b>CMSIS doc for SPI from ARM</b></a>,
137- <a href="https://www.keil.com/pack/doc/CMSIS/Driver/html/group__spi__interface__gr.html" target=_blank><b>CMSIS doc for SPI from KEIL</b></a>
138
139\n The codes for SPI is at:
140- \ref Spi.c
141- \ref Spi.h
142
143*/
144/*!
145
146*/
147extern ARM_DRIVER_SPI Driver_SPI0; // Viene inclusa la Periferica SPI0
148ARM_DRIVER_SPI *SPIdrv= &Driver_SPI0; // Viene creato un puntatore a Driver_SPI0
149//extern ARM_DRIVER_SPI Driver_SPI2; // Viene inclusa la Periferica SPI2
150//ARM_DRIVER_SPI *SPIdrv= &Driver_SPI2; // Viene creato un puntatore a Driver_SPI2
151uint32_t evento_SPI; ///< This is the variable which resembles the flags from the communication
152uint32_t SPI_speed = SPI_DAC_SPEED; //!< The speed to be set to SPI. It could varies from chip to chip
153
154// Viene inizializzato un parametro
155//int32_t status;
156
157/******************************************************************************
158 Callback della Periferica SPI
159 ******************************************************************************/
160
161//Inizio CROSS
162 /*! \brief After that the SPI ends its operations and the interrupt is generated this signal function is called which marks errors, if any
163 and flags of operation done.
164
165*\param[in] event
166*\return No parameters
167 \showrefby
168\showrefs
169
170*\snippet{lineno} SPI.c fun_SPI_callback
171 */
172//! <!-- [fun_SPI_callback] -->
173void SPI_callback(uint32_t event)
174{
175 evento_SPI =event; //We make the event global
176 switch (event)
177 {
178 case ARM_SPI_EVENT_TRANSFER_COMPLETE:
179 {
181 break;
182 }
183 case ARM_SPI_EVENT_DATA_LOST:
184 {
186 break;
187 }
188 case ARM_SPI_EVENT_MODE_FAULT:
189 {
191 break;
192 }
193 }
194}
195//! <!-- [fun_SPI_callback] -->
196
197/*! \brief SPI is initialized here. Its ise t at 8 bits and 100 KHz, as default
198
199*\return No parameters
200\showrefby
201\showrefs
202*\snippet{lineno} SPI.c fun_SPI_Inizialize
203 */
204//! <!-- [fun_SPI_Inizialize] -->
205void SPI_Inizialize(void){
206// int32_t status;
207 SPIdrv->PowerControl (ARM_POWER_OFF); // Terminate any pending transfers, reset IRQ/DMA, power off peripheral
208 SPIdrv->Uninitialize ();
209 status = SPIdrv->Initialize (SPI_callback); // Viene inizializzata la Periferica SPI
210 status = SPIdrv->PowerControl(ARM_POWER_FULL); // Viene accesa la Periferica SPI
211
212 status = SPIdrv->Control(SPI_control_for_relay_driver,spi_clock_for_relais); //SPI initialization to relay driver by default
213// status = SPIdrv->Control (ARM_SPI_SET_BUS_SPEED, spi_clock_for_relais); //spi_clock_for_relais is our setting
214 // Viene configurata la linea SS: INACTIVE = HIGH
215 SPIdrv->Control (ARM_SPI_CONTROL_SS, ARM_SPI_SS_INACTIVE);
216}
217//! <!-- [fun_SPI_Inizialize] -->
218
219//Fine CROSS
220
221/*****************************************************************************
222 Inizializzazione della Periferica SPI
223******************************************************************************/
224
225
226/*****************************************************************************
227 Inizializzazione della Periferica SPI per il DAC
228******************************************************************************/
229 /*! \brief SPI is initialized here for DAC. Remember to set the variable SPI_speed before the call. This function is becoming obsolote.
230
231*\return No parameters
232 \showrefby
233\showrefs
234*\snippet{lineno} SPI.c fun_SPI_Inizialize_per_il_DAC
235 */
236//! <!-- [fun_SPI_Inizialize_per_il_DAC] -->
238{
239
240 SPIdrv->PowerControl (ARM_POWER_OFF); // Terminate any pending transfers, reset IRQ/DMA, power off peripheral
241 SPIdrv->Uninitialize ();
242// Al DAC servono data bit di 16 bit
243 SPIdrv->Initialize (SPI_callback); // Viene inizializzata la Periferica SPI
244 SPIdrv->PowerControl(ARM_POWER_FULL); // Viene accesa la Periferica SPI
245
246 // Viene configurato SPI: Master, modalit\'a 16 bit, 10000 Kbit/sec
247 SPIdrv->Control (SPI_control_for_DAC , SPI_speed); // Viene impostata la modalit\'a a 16 bit
248 // Viene configurata la linea SS: INACTIVE = HIGH
249 SPIdrv->Control (ARM_SPI_CONTROL_SS, ARM_SPI_SS_INACTIVE);
250}
251//! <!-- [fun_SPI_Inizialize_per_il_DAC] -->
252
253
254/*****************************************************************************
255 SPItx_16_per_il_DAC
256******************************************************************************/
257void SPItx_16_per_il_DAC(uint16_t dato)
258{
259// Trasmissione di 2 byte via SPI
260 LPC_SPI->SPDR=dato; // Viene trasmesso il dato
261 while (!((LPC_SPI->SPSR & 0x80) == 0x80)){} // Si attende che il flag SPIF si alzi
262 dato=LPC_SPI->SPSR; // Dummy op per azzerare lo status reg
263 dato=LPC_SPI->SPDR; // Dummy op necessaria
264}
265
266
267/*****************************************************************************
268 SPIrx
269******************************************************************************/
270unsigned char SPIrx(void)
271{
272// Ricezione di 1 byte via SPI
273 unsigned char dato;
274 LPC_SPI->SPDR=0x00; // Viene trasmesso zero
275 while (!((LPC_SPI->SPSR&0x80) == 0x80)){} // Si attende che il flag SPIF si alzi
276 dato=LPC_SPI->SPSR; // Dummy op per azzerare lo status reg
277 dato=LPC_SPI->SPDR; // Viene letto il dato
278 return dato;
279}
280
281
282/*****************************************************************************
283 SPIrx24
284******************************************************************************/
285unsigned long int SPIrx24(void)
286{
287// Ricezione di 24 bit via SPI (msb first)
288 unsigned long int dato;
289 dato=SPIrx()<<16; // Vengono letti i primi 8 bit
290 dato=dato+(SPIrx()<<8); // Vengono letti i secondi 8 bit
291 dato=dato+SPIrx(); // Vengono letti gli ultimi 8 bit
292 return dato;
293}
#define spi_clock_for_relais
[ref_spi_clock_for_relais]
volatile uint32_t Error_bad_operation
exploited to mark the errors
void SPI_callback(uint32_t event)
After that the SPI ends its operations and the interrupt is generated this signal function is called ...
Definition: Spi.c:173
void SPI_Inizialize_per_il_DAC(void)
SPI is initialized here for DAC. Remember to set the variable SPI_speed before the call....
Definition: Spi.c:237
uint32_t SPI_speed
The speed to be set to SPI. It could varies from chip to chip.
Definition: Spi.c:152
void SPI_Inizialize(void)
SPI is initialized here. Its ise t at 8 bits and 100 KHz, as default.
Definition: Spi.c:205
uint32_t evento_SPI
This is the variable which resembles the flags from the communication.
Definition: Spi.c:151
#define SPI_control_for_relay_driver
[ref_SPI_control_for_relay_driver]
Definition: Spi.h:10
#define SPI_DAC_SPEED
Definition: Spi.h:7
#define SPI_control_for_DAC
[ref_SPI_control_for_relay_driver]
Definition: Spi.h:13