KM3NeT CLB  2.0
KM3NeT CLB v2 Embedded Software
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
spi.c
1 /*
2  * spi.c
3  *
4  * Created on: 2 apr. 2013
5  * Author: vincentb
6  */
7 
8 #include "drv/wb/spi.h"
9 
10 
11 #include "cfg_soc.h"
12 
13 #include <assert.h>
14 #include <string.h>
15 #include <stdio.h>
16 
17 #include "kernel/err.h"
18 #include "kernel/tm.h"
19 #include "errorcode.h"
20 
21 #define _SPI_MASK_ALL 0xFFFFFFFF
22 
23 // Part of trick to allow writing of adress 0.
24 #define _SPI_ADDR_ZERO ((uint8_t *)0xFFFFFFFF)
25 
26 // #define _SPI_DEBUG
27 
28 static void spiRMW(_reg_t * reg, _reg_t val, _reg_t mask)
29 {
30  _reg_t tmp = *reg;
31  if ( ( tmp & mask ) == ( val & mask ) ) return;
32  tmp = (tmp & ~mask) | (val & mask);
33  *reg = tmp;
34 }
35 
36 #define SPI_FLAG( REG, BOOL, FLAG ) \
37  spiRMW( REG, ( BOOL ) ? FLAG : 0, FLAG)
38 
39 bool spiInit(SPI_Device * dev, SpiInit * init)
40 {
41 
42  assert(init->mode <= 3);
43  assert(init->bitrate <= SPI_MAX_BITRATE); // maximum frequency
44  assert(init->bitrate >= SPI_MIN_BITRATE); // minimum frequency
45 
46  int div = ( WISHBONE_FREQ / ( init->bitrate * 2 )) - 1;
47  dev->DIVIDER = div;
48 
49 
50  // clear control register
51  dev->CTL = 0;
52 
53  const uint16_t mode[] = {
55 
56  spiRMW( &dev->CTL, mode[init->mode], SPI_CTL_MODE_MASK);
57 
58  SPI_FLAG( &dev->CTL, init->intEnable , SPI_CTL_IE);
59  SPI_FLAG( &dev->CTL, init->lsbFirst , SPI_CTL_LSB);
60 
61  // first run SPI always fails... we'll clock 8 bits out, without CS
62  // ----------------------------------------------------------------
63  SPI_FLAG( &dev->CTL, false , SPI_CTL_ASS);
64 
65  spiRMW( &dev->CTL, 8 & SPI_CTL_CHAR_LEN_MASK, SPI_CTL_CHAR_LEN_MASK);
66  dev->CTL |= SPI_CTL_GO_BSY;
67  uint32_t to = timeOutInit(500);
68 
69  while (dev->CTL & SPI_CTL_GO_BSY)
70  {
71  if (timeOut(to))
72  {
73  return errSet(ERROR(E_SPI_TIMEOUT));
74  }
75  }
76  // ----------------------------------------------------------------
77  // endif
78 
79  SPI_FLAG( &dev->CTL, init->autoSlaveSelect , SPI_CTL_ASS);
80 
81 
82 
83 
84  return true;
85 }
86 
87 
88 
89 void spiAsyncTx(SPI_Device * dev, uint8_t * dataIn, int clen)
90 {
91  assert(clen > 0 && clen <= SPI_MAX_BYTES );
92  dev->CTL &= ~SPI_CTL_GO_BSY;
93  spiRMW( &dev->CTL, ( clen * 8 ) & SPI_CTL_CHAR_LEN_MASK, SPI_CTL_CHAR_LEN_MASK);
94  if (dataIn != NULL)
95  {
96  if (dataIn == _SPI_ADDR_ZERO) dataIn = 0;
97 
98  uint32_t t = 0;
99 
100 
101  while (clen > 0)
102  {
103 // printf("Clen=%d\n", clen);
104  t <<= 8;
105  t |= *dataIn;
106  clen--;
107  if (clen % 4 == 0) {
108  dev->TRX[clen / 4] = t;
109 // printf("Set reg: %08x\n", t);
110  t = 0;
111  }
112  dataIn++;
113  }
114 
115 
116  } else {
117  dev->TRX[0] = 0;
118  dev->TRX[1] = 0;
119  dev->TRX[2] = 0;
120  dev->TRX[3] = 0;
121  }
122 #ifdef _SPI_DEBUG
123  int i;
124  for (i = 0; i < 4; ++i) printf("SPI TX Reg %i: %08x\n", i, dev->TRX[i]);
125 #endif
126 
127 
128 // printf("TX0: %08x\n", dev->TRX[0]);
129  dev->CTL |= SPI_CTL_GO_BSY;
130 }
131 
133 {
134  return ( dev->CTL & SPI_CTL_GO_BSY ) != 0;
135 }
136 
138 {
139 
140  return ((( ( dev->CTL & SPI_CTL_CHAR_LEN_MASK ) - 1 ) & SPI_CTL_CHAR_LEN_MASK ) + 1 ) / 8;
141 }
142 
143 void spiASyncRx(SPI_Device * dev, uint8_t * dataOut)
144 {
145  dev->CTL &= ~SPI_CTL_GO_BSY;
146 
147 
148  int clen = spiASyncLength(dev) - 1;
149 
150 #ifdef _SPI_DEBUG
151  int i;
152  for (i = 0; i < 4; ++i) printf("SPI RX Reg %i: %08x\n", i, dev->TRX[i]);
153 #endif
154  while (clen >= 0)
155  {
156  *dataOut = 0xFF & ( dev->TRX[clen / 4] >> ((clen % 4) * 8));
157  dataOut++;
158  clen--;
159  }
160 
161 }
162 
163 
164 static bool spiTxRxPart(SPI_Device * dev, uint8_t * dataIn, uint8_t * dataOut, int len)
165 {
166  if (dataIn == NULL && dataOut == NULL)
167  {
168  // as it makes no sense to both pass 0 as dataIn and dataOut, we'll assume
169  // data is being read from address 0. This is *only* possible as we know
170  // this happens when dumping the core memory when an error occurs.
171  //
172  // So, its not really pretty.
173  dataIn = _SPI_ADDR_ZERO;
174  }
175  spiAsyncTx(dev, dataIn, len);
176 
177  uint32_t to = timeOutInit(500);
178 
179  while (dev->CTL & SPI_CTL_GO_BSY)
180  {
181  if (timeOut(to))
182  {
183  return errSet(ERROR(E_SPI_TIMEOUT));
184  }
185  }
186 
187  if (dataOut != NULL) spiASyncRx(dev, dataOut);
188 
189  return true;
190 }
191 
192 bool spiTxRx(SPI_Device * dev, uint8_t * dataIn, uint8_t * dataOut, int len)
193 {
194  while (len > SPI_MAX_BYTES) {
195  if (!spiTxRxPart(dev, dataIn, dataOut, SPI_MAX_BYTES)) return false;
196  len -= SPI_MAX_BYTES;
197  if (dataIn != NULL) dataIn += SPI_MAX_BYTES;
198  if (dataOut != NULL) dataOut += SPI_MAX_BYTES;
199  }
200  return spiTxRxPart(dev, dataIn, dataOut, len);
201 }
202 
203 
204 void spiSelect(SPI_Device * dev, uint32_t slaveNo)
205 {
206  assert(slaveNo < SPI_MAX_SLAVE);
207 
208  //dev->SS |= 1 << slaveNo;
209  dev->SS = 0xFF;
210 }
211 
213 {
214  dev->SS = 0;
215 }
SPI initialization structure.
Definition: spi.h:91
Defines the configuration of the LM32 SOC for the CLBv2.
uint8_t mode
SPI mode (0 - 3, see Wikipedia, 0 - default).
Definition: spi.h:94
bool lsbFirst
Transfer LSB first.
Definition: spi.h:95
void spiSelect(SPI_Device *dev, uint32_t slaveNo)
Selects a specific slave.
Definition: spi.c:204
#define SPI_MIN_BITRATE
Minimum SPI bitrate.
Definition: spi.h:76
Structure defines OpenCores SPI Device.
Definition: dev_spi.h:57
#define SPI_CTL_CHAR_LEN_MASK
Number of bits to transfer in one go MASK.
Definition: dev_spi.h:35
void spiASyncRx(SPI_Device *dev, uint8_t *dataOut)
Reads the data received in the previous transmission.
Definition: spi.c:143
volatile unsigned int CTL
Control.
Definition: dev_spi.h:60
#define SPI_CTL_LSB
Least Significant Bit first (opposed to MSB)
Definition: dev_spi.h:47
#define E_SPI_TIMEOUT
SPI transmission timeout.
Definition: spi.h:80
This driver wraps the functions of the OpenCores SPI master.
int spiASyncLength(SPI_Device *dev)
Last lenght of data transmitted.
Definition: spi.c:137
#define SPI_CTL_MODE_3
SPI mode 3 (CPOL = 1, CHPA = 1) (See node)
Definition: dev_spi.h:45
#define SPI_MAX_SLAVE
Maximum number of slaves (0 - SPI_MAX_SLAVE - 1)
Definition: spi.h:73
#define SPI_CTL_ASS
Auto slave select.
Definition: dev_spi.h:49
static uint32_t timeOutInit(uint32_t msec)
Initializes a timeout with the specified no of msecs.
Definition: tm.h:53
#define SPI_CTL_MODE_2
SPI mode 2 (CPOL = 1, CHPA = 0) (See note)
Definition: dev_spi.h:44
bool spiASyncBusy(SPI_Device *dev)
Returns whether or not the SPI driver is busy tranceiving data.
Definition: spi.c:132
#define SPI_CTL_MODE_MASK
SPI mode mask.
Definition: dev_spi.h:41
#define SPI_MAX_BYTES
The maximum bytes the SPI driver can transfer at a time.
Definition: spi.h:72
uint32_t bitrate
Bit-rate.
Definition: spi.h:93
static bool timeOut(uint32_t to)
Checks whether or not the timeout has expired.
Definition: tm.h:77
Manages the global system error.
bool spiInit(SPI_Device *dev, SpiInit *init)
Initializes the specified SPI device with the specified parameters.
Definition: spi.c:39
#define SPI_MAX_BITRATE
Maximum SPI bitrate.
Definition: spi.h:78
Simple timer functions.
#define SPI_CTL_MODE_0
SPI mode 0 (CPOL = 0, CHPA = 0)
Definition: dev_spi.h:42
void spiAsyncTx(SPI_Device *dev, uint8_t *dataIn, int length)
Start a asynchronous SPI transmission.
Definition: spi.c:89
void spiDeselect(SPI_Device *dev)
Deselects all slaves.
Definition: spi.c:212
volatile unsigned int DIVIDER
Divider.
Definition: dev_spi.h:61
This module is responsible for distributing error codes.
bool autoSlaveSelect
Auto slave select.
Definition: spi.h:97
#define SPI_CTL_GO_BSY
Start Transfer / Busy.
Definition: dev_spi.h:37
bool spiTxRx(SPI_Device *dev, uint8_t *dataIn, uint8_t *dataOut, int len)
Transfers a specific number of bytes in a synchronous way.
Definition: spi.c:192
bool errSet(uint32_t code, const char *error, const char *name)
Sets an error.
#define ERROR(CODE,...)
Expands an error code to an error code with a description (if ERROR_W_DESCR is declared).
#define SPI_CTL_IE
Interrupt enable.
Definition: dev_spi.h:48
volatile unsigned int SS
Slave Select.
Definition: dev_spi.h:62
#define _reg_t
Basic register type.
Definition: dev_defs.h:30
volatile unsigned int TRX[4]
Tx/Rx registers.
Definition: dev_spi.h:59
bool intEnable
Interrupts enabled (not implemented yet).
Definition: spi.h:96
#define SPI_CTL_MODE_1
SPI mode 1 (CPOL = 0, CHPA = 1)
Definition: dev_spi.h:43