Contiki-Inga 3.x
Communication.c
1 /*
2  * Copyright (c) 2014, Analog Devices, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * 3. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /**
32  * \author Dragos Bogdan <Dragos.Bogdan@Analog.com>, Ian Martin <martini@redwirellc.com>
33  */
34 
35 /******************************************************************************/
36 /***************************** Include Files **********************************/
37 /******************************************************************************/
38 
39 #include <stdint.h>
40 
41 #include "rl78.h"
42 
43 #include "Communication.h" /* Communication definitions */
44 
45 #ifndef NOP
46 #define NOP asm ("nop")
47 #endif
48 
49 /* Enable interrupts: */
50 #ifndef EI
51 #ifdef __GNUC__
52 #define EI asm ("ei");
53 #else
54 #define EI __enable_interrupt();
55 #endif
56 #endif
57 
58 #undef BIT
59 #define BIT(n) (1 << (n))
60 
61 #define CLK_SCALER (0x4)
62 #define SCALED_CLK (f_CLK / (1 << CLK_SCALER))
63 #define BITBANG_SPI 1
64 
65 char IICA0_Flag;
66 
67 /******************************************************************************/
68 /************************ Functions Definitions *******************************/
69 /******************************************************************************/
70 
71 /***************************************************************************//**
72  * @brief I2C interrupt service routine.
73  *
74  * @return None.
75  *******************************************************************************/
76 /*__interrupt */ static void
77 IICA0_Interrupt(void)
78 {
79  IICA0_Flag = 1;
80 }
81 /***************************************************************************//**
82  * @brief Initializes the SPI communication peripheral.
83  *
84  * @param lsbFirst - Transfer format (0 or 1).
85  * Example: 0x0 - MSB first.
86  * 0x1 - LSB first.
87  * @param clockFreq - SPI clock frequency (Hz).
88  * Example: 1000 - SPI clock frequency is 1 kHz.
89  * @param clockPol - SPI clock polarity (0 or 1).
90  * Example: 0x0 - Idle state for clock is a low level; active
91  * state is a high level;
92  * 0x1 - Idle state for clock is a high level; active
93  * state is a low level.
94  * @param clockEdg - SPI clock edge (0 or 1).
95  * Example: 0x0 - Serial output data changes on transition
96  * from idle clock state to active clock state;
97  * 0x1 - Serial output data changes on transition
98  * from active clock state to idle clock state.
99  *
100  * @return status - Result of the initialization procedure.
101  * Example: 0 - if initialization was successful;
102  * -1 - if initialization was unsuccessful.
103  *******************************************************************************/
104 char
105 SPI_Init(enum CSI_Bus bus,
106  char lsbFirst,
107  long clockFreq,
108  char clockPol,
109  char clockEdg)
110 {
111 #if BITBANG_SPI
112  PIOR5 = 1; /* Move SPI/I2C/UART functions from Port 0 pins 2-4 to Port 8. */
113 
114  /* Configure SCLK as an output. */
115  PM0 &= ~BIT(4);
116  POM0 &= ~BIT(4);
117 
118  /* Configure MOSI as an output: */
119  PM0 &= ~BIT(2);
120  POM0 &= ~BIT(2);
121  PMC0 &= ~BIT(2);
122 
123  /* Configure MISO as an input: */
124  PM0 |= BIT(3);
125  PMC0 &= ~BIT(3);
126 #else
127  char sdrValue = 0;
128  char delay = 0;
129  uint16_t scr;
130  uint8_t shift;
131 
132  PIOR5 = 0; /* Keep SPI functions on Port 0 pins 2-4. */
133 
134  /* Enable input clock supply. */
135  if(bus <= CSI11) {
136  SAU0EN = 1;
137  } else { SAU1EN = 1;
138  }
139 
140  /* After setting the SAUmEN bit to 1, be sure to set serial clock select
141  register m (SPSm) after 4 or more fCLK clocks have elapsed. */
142  NOP;
143  NOP;
144  NOP;
145  NOP;
146 
147  /* Select the fCLK as input clock. */
148  if(bus <= CSI11) {
149  SPS0 = (CLK_SCALER << 4) | CLK_SCALER; /* TODO: kludge */
150  } else { SPS1 = (CLK_SCALER << 4) | CLK_SCALER; /* TODO: kludge */
151  }
152  /* Select the CSI operation mode. */
153  switch(bus) {
154  case CSI00: SMR00 = 0x0020;
155  break;
156  case CSI01: SMR01 = 0x0020;
157  break;
158  case CSI10: SMR02 = 0x0020;
159  break;
160  case CSI11: SMR03 = 0x0020;
161  break;
162  case CSI20: SMR10 = 0x0020;
163  break;
164  case CSI21: SMR11 = 0x0020;
165  break;
166  case CSI30: SMR12 = 0x0020;
167  break;
168  case CSI31: SMR13 = 0x0020;
169  break;
170  }
171 
172  clockPol = 1 - clockPol;
173  scr = (clockEdg << 13) |
174  (clockPol << 12) |
175  0xC000 | /* Operation mode: Transmission/reception. */
176  0x0007; /* 8-bit data length. */
177  switch(bus) {
178  case CSI00: SCR00 = scr;
179  break;
180  case CSI01: SCR01 = scr;
181  break;
182  case CSI10: SCR02 = scr;
183  break;
184  case CSI11: SCR03 = scr;
185  break;
186  case CSI20: SCR10 = scr;
187  break;
188  case CSI21: SCR11 = scr;
189  break;
190  case CSI30: SCR12 = scr;
191  break;
192  case CSI31: SCR13 = scr;
193  break;
194  }
195 
196  /* clockFreq = mckFreq / (sdrValue * 2 + 2) */
197  sdrValue = SCALED_CLK / (2 * clockFreq) - 1;
198  sdrValue <<= 9;
199  switch(bus) {
200  case CSI00: SDR00 = sdrValue;
201  break;
202  case CSI01: SDR01 = sdrValue;
203  break;
204  case CSI10: SDR02 = sdrValue;
205  break;
206  case CSI11: SDR03 = sdrValue;
207  break;
208  case CSI20: SDR10 = sdrValue;
209  break;
210  case CSI21: SDR11 = sdrValue;
211  break;
212  case CSI30: SDR12 = sdrValue;
213  break;
214  case CSI31: SDR13 = sdrValue;
215  break;
216  }
217 
218  /* Set the clock and data initial level. */
219  clockPol = 1 - clockPol;
220  shift = bus & 0x3;
221  if(bus <= CSI11) {
222  SO0 &= ~(0x0101 << shift);
223  SO0 |= ((clockPol << 8) | clockPol) << shift;
224  } else {
225  SO1 &= ~(0x0101 << shift);
226  SO1 |= ((clockPol << 8) | clockPol) << shift;
227  }
228 
229  /* Enable output for serial communication operation. */
230  switch(bus) {
231  case CSI00: SOE0 |= BIT(0);
232  break;
233  case CSI01: SOE0 |= BIT(1);
234  break;
235  case CSI10: SOE0 |= BIT(2);
236  break;
237  case CSI11: SOE0 |= BIT(3);
238  break;
239  case CSI20: SOE1 |= BIT(0);
240  break;
241  case CSI21: SOE1 |= BIT(1);
242  break;
243  case CSI30: SOE1 |= BIT(2);
244  break;
245  case CSI31: SOE1 |= BIT(3);
246  break;
247  }
248 
249  switch(bus) {
250  case CSI00:
251  /* SO00 output: */
252  P1 |= BIT(2);
253  PM1 &= ~BIT(2);
254 
255  /* SI00 input: */
256  PM1 |= BIT(1);
257 
258  /* SCK00N output: */
259  P1 |= BIT(0);
260  PM1 &= ~BIT(0);
261  break;
262 
263  case CSI01:
264  /* SO01 output: */
265  P7 |= BIT(3);
266  PM7 &= ~BIT(3);
267 
268  /* SI01 input: */
269  PM7 |= BIT(4);
270 
271  /* SCK01 output: */
272  P7 |= BIT(5);
273  PM7 &= ~BIT(5);
274  break;
275 
276  case CSI10:
277  PMC0 &= ~BIT(2); /* Disable analog input on SO10. */
278 
279  /* SO10 output: */
280  P0 |= BIT(2);
281  PM0 &= ~BIT(2);
282 
283  /* SI10 input: */
284  PM0 |= BIT(3);
285 
286  /* SCK10N output: */
287  P0 |= BIT(4);
288  PM0 &= ~BIT(4);
289  break;
290 
291  case CSI11:
292  /* SO11 output: */
293  P5 |= BIT(1);
294  PM5 &= ~BIT(1);
295 
296  /* SI11 input: */
297  PM5 |= BIT(0);
298 
299  /* SCK11 output: */
300  P3 |= BIT(0);
301  PM3 &= ~BIT(0);
302  break;
303 
304  case CSI20:
305  /* SO20 output: */
306  P1 |= BIT(3);
307  PM1 &= ~BIT(3);
308 
309  /* SI20 input: */
310  PM1 |= BIT(4);
311 
312  /* SCK20 output: */
313  P1 |= BIT(5);
314  PM1 &= ~BIT(5);
315  break;
316 
317  case CSI21:
318  /* SO21 output: */
319  P7 |= BIT(2);
320  PM7 &= ~BIT(2);
321 
322  /* SI21 input: */
323  PM7 |= BIT(1);
324 
325  /* SCK21 output: */
326  P7 |= BIT(0);
327  PM7 &= ~BIT(0);
328  break;
329 
330  case CSI30:
331  /* TODO: not supported */
332  break;
333  case CSI31:
334  /* TODO: not supported */
335  break;
336  }
337 
338  /* Wait for the changes to take place. */
339  for(delay = 0; delay < 50; delay++) {
340  NOP;
341  }
342 
343  /* Set the SEmn bit to 1 and enter the communication wait status */
344  switch(bus) {
345  case CSI00: SS0 = BIT(0);
346  break;
347  case CSI01: SS0 = BIT(1);
348  break;
349  case CSI10: SS0 = BIT(2);
350  break;
351  case CSI11: SS0 = BIT(3);
352  break;
353  case CSI20: SS1 = BIT(0);
354  break;
355  case CSI21: SS1 = BIT(1);
356  break;
357  case CSI30: SS1 = BIT(2);
358  break;
359  case CSI31: SS1 = BIT(3);
360  break;
361  }
362 
363  /* Sanity check: */
364  if(bus == CSI10) {
365  /* MOSI: */
366  PIOR5 = 0;
367  PMC02 = 0;
368  PM02 = 0;
369  P02 = 1;
370 
371  /* MISO: */
372  PIOR5 = 0;
373  PMC03 = 0;
374  PM03 = 1;
375 
376  /* SCLK: */
377  PIOR5 = 0;
378  PM04 = 0;
379  P04 = 1;
380  }
381 #endif
382 
383  return 0;
384 }
385 /***************************************************************************//**
386  * @brief Writes data to SPI.
387  *
388  * @param slaveDeviceId - The ID of the selected slave device.
389  * @param data - Data represents the write buffer.
390  * @param bytesNumber - Number of bytes to write.
391  *
392  * @return Number of written bytes.
393  *******************************************************************************/
394 #if 0
395 char
396 SPI_Write(enum CSI_Bus bus,
397  char slaveDeviceId,
398  unsigned char *data,
399  char bytesNumber)
400 {
401  char byte = 0;
402  unsigned char read = 0;
403  unsigned short originalSCR = 0;
404  unsigned short originalSO1 = 0;
405 
406  volatile uint8_t *sio;
407  volatile uint16_t *ssr;
408 
409  switch(bus) {
410  default:
411  case CSI00: sio = &SIO00;
412  ssr = &SSR00;
413  break;
414  case CSI01: sio = &SIO01;
415  ssr = &SSR01;
416  break;
417  case CSI10: sio = &SIO10;
418  ssr = &SSR02;
419  break;
420  case CSI11: sio = &SIO11;
421  ssr = &SSR03;
422  break;
423  case CSI20: sio = &SIO20;
424  ssr = &SSR10;
425  break;
426  case CSI21: sio = &SIO21;
427  ssr = &SSR11;
428  break;
429  case CSI30: sio = &SIO30;
430  ssr = &SSR12;
431  break;
432  case CSI31: sio = &SIO31;
433  ssr = &SSR13;
434  break;
435  }
436 
437  for(byte = 0; byte < bytesNumber; byte++) {
438  *sio = data[byte];
439  NOP;
440  while(*ssr & 0x0040) ;
441  read = *sio;
442  }
443 
444  return bytesNumber;
445 }
446 #endif
447 
448 #if BITBANG_SPI
449 #define sclk_low() (P0 &= ~BIT(4))
450 #define sclk_high() (P0 |= BIT(4))
451 #define mosi_low() (P0 &= ~BIT(2))
452 #define mosi_high() (P0 |= BIT(2))
453 #define read_miso() (P0bits.bit3)
454 
455 static unsigned char
456 spi_byte_exchange(unsigned char tx)
457 {
458  unsigned char rx = 0, n = 0;
459 
460  sclk_low();
461 
462  for(n = 0; n < 8; n++) {
463  if(tx & 0x80) {
464  mosi_high();
465  } else { mosi_low();
466  }
467 
468  /* The slave samples MOSI at the rising-edge of SCLK. */
469  sclk_high();
470 
471  rx <<= 1;
472  rx |= read_miso();
473 
474  tx <<= 1;
475 
476  /* The slave changes the value of MISO at the falling-edge of SCLK. */
477  sclk_low();
478  }
479 
480  return rx;
481 }
482 #endif
483 
484 /***************************************************************************//**
485  * @brief Reads data from SPI.
486  *
487  * @param slaveDeviceId - The ID of the selected slave device.
488  * @param data - Data represents the write buffer as an input parameter
489  * and the read buffer as an output parameter.
490  * @param bytesNumber - Number of bytes to read.
491  *
492  * @return Number of read bytes.
493  *******************************************************************************/
494 char
495 SPI_Read(enum CSI_Bus bus,
496  char slaveDeviceId,
497  unsigned char *data,
498  char bytesNumber)
499 {
500 #if BITBANG_SPI
501  unsigned char n = 0;
502  for(n = 0; n < bytesNumber; n++) {
503  data[n] = spi_byte_exchange(data[n]);
504  }
505 #else
506  char byte = 0;
507  unsigned short originalSCR = 0;
508  unsigned short originalSO1 = 0;
509 
510  volatile uint8_t *sio;
511  volatile uint16_t *ssr;
512  char dummy;
513 
514  switch(bus) {
515  default:
516  case CSI00: sio = &SIO00;
517  ssr = &SSR00;
518  break;
519  case CSI01: sio = &SIO01;
520  ssr = &SSR01;
521  break;
522  case CSI10: sio = &SIO10;
523  ssr = &SSR02;
524  break;
525  case CSI11: sio = &SIO11;
526  ssr = &SSR03;
527  break;
528  case CSI20: sio = &SIO20;
529  ssr = &SSR10;
530  break;
531  case CSI21: sio = &SIO21;
532  ssr = &SSR11;
533  break;
534  case CSI30: sio = &SIO30;
535  ssr = &SSR12;
536  break;
537  case CSI31: sio = &SIO31;
538  ssr = &SSR13;
539  break;
540  }
541 
542  /* Flush the receive buffer: */
543  while(*ssr & 0x0020) dummy = *sio;
544  (void)dummy;
545 
546  for(byte = 0; byte < bytesNumber; byte++) {
547  *sio = data[byte];
548  NOP;
549  while(*ssr & 0x0040) ;
550  data[byte] = *sio;
551  }
552 #endif
553 
554  return bytesNumber;
555 }
556 /***************************************************************************//**
557  * @brief Initializes the I2C communication peripheral.
558  *
559  * @param clockFreq - I2C clock frequency (Hz).
560  * Example: 100000 - SPI clock frequency is 100 kHz.
561  * @return status - Result of the initialization procedure.
562  * Example: 0 - if initialization was successful;
563  * -1 - if initialization was unsuccessful.
564  *******************************************************************************/
565 char
566 I2C_Init(long clockFreq)
567 {
568  long fckFreq = 32000000;
569  unsigned char wlValue = 0;
570  unsigned char whValue = 0;
571 
572  (void)IICA0_Interrupt; /* Prevent an unused-function warning. */
573 
574  /* Enable interrupts */
575  EI;
576 
577  /* Enable input clock supply. */
578  IICA0EN = 1;
579 
580  /* Set the fast mode plus operation. */
581  SMC0 = 1;
582 
583  /* Set transfer rate. */
584  wlValue = (unsigned char)((0.5 * fckFreq) / clockFreq);
585  whValue = (unsigned char)(wlValue - (fckFreq / (10 * clockFreq)));
586  IICWL0 = wlValue;
587  IICWH0 = whValue;
588 
589  STCEN0 = 1; /* After operation is enabled, enable generation of a start */
590  /* condition without detecting a stop condition. */
591  WTIM0 = 1; /* Interrupt request is generated at the ninth clock’s */
592  /* falling edge. */
593 
594  /* Enable I2C operation. */
595  IICE0 = 1;
596 
597  /* Configure SCLA0 and SDAA0 pins as digital output. */
598  P6 &= ~0x03;
599  PM6 &= ~0x03;
600 
601  return 0;
602 }
603 /***************************************************************************//**
604  * @brief Writes data to a slave device.
605  *
606  * @param slaveAddress - Adress of the slave device.
607  * @param dataBuffer - Pointer to a buffer storing the transmission data.
608  * @param bytesNumber - Number of bytes to write.
609  * @param stopBit - Stop condition control.
610  * Example: 0 - A stop condition will not be sent;
611  * 1 - A stop condition will be sent.
612  *
613  * @return status - Number of read bytes or 0xFF if the slave address was
614  * not acknowledged by the device.
615  *******************************************************************************/
616 char
617 I2C_Write(char slaveAddress,
618  unsigned char *dataBuffer,
619  char bytesNumber,
620  char stopBit)
621 {
622  char byte = 0;
623  char status = 0;
624 
625  IICAMK0 = 1; /* Interrupt servicing disabled. */
626  STT0 = 1; /* Generate a start condition. */
627  IICAMK0 = 0; /* Interrupt servicing enabled. */
628 
629  /* Send the first byte. */
630  IICA0_Flag = 0;
631  IICA0 = (slaveAddress << 1);
632  while(IICA0_Flag == 0) ;
633 
634  if(ACKD0) { /* Acknowledge was detected. */
635  for(byte = 0; byte < bytesNumber; byte++) {
636  IICA0_Flag = 0;
637  IICA0 = *dataBuffer;
638  while(IICA0_Flag == 0) ;
639  dataBuffer++;
640  }
641  status = bytesNumber;
642  } else { /* Acknowledge was not detected. */
643  status = 0xFF;
644  }
645  if(stopBit) {
646  SPT0 = 1; /* Generate a stop condition. */
647  while(IICBSY0) ; /* Wait until the I2C bus status flag is cleared. */
648  }
649 
650  return status;
651 }
652 /***************************************************************************//**
653  * @brief Reads data from a slave device.
654  *
655  * @param slaveAddress - Adress of the slave device.
656  * @param dataBuffer - Pointer to a buffer that will store the received data.
657  * @param bytesNumber - Number of bytes to read.
658  * @param stopBit - Stop condition control.
659  * Example: 0 - A stop condition will not be sent;
660  * 1 - A stop condition will be sent.
661  *
662  * @return status - Number of read bytes or 0xFF if the slave address was
663  * not acknowledged by the device.
664  *******************************************************************************/
665 char
666 I2C_Read(char slaveAddress,
667  unsigned char *dataBuffer,
668  char bytesNumber,
669  char stopBit)
670 {
671  char byte = 0;
672  char status = 0;
673 
674  IICAMK0 = 1; /* Interrupt servicing disabled. */
675  STT0 = 1; /* Generate a start condition. */
676  IICAMK0 = 0; /* Interrupt servicing enabled. */
677 
678  /* Send the first byte. */
679  IICA0_Flag = 0;
680  IICA0 = (slaveAddress << 1) + 1;
681  while(IICA0_Flag == 0) ;
682 
683  if(ACKD0) { /* Acknowledge was detected. */
684  ACKE0 = 1; /* Enable acknowledgment. */
685  for(byte = 0; byte < bytesNumber; byte++) {
686  if(byte == (bytesNumber - 1)) {
687  ACKE0 = 0U; /* Disable acknowledgment. */
688  }
689  WREL0 = 1U; /* Cancel wait. */
690  IICA0_Flag = 0;
691  while(IICA0_Flag == 0) ;
692  *dataBuffer = IICA0;
693  dataBuffer++;
694  }
695  status = bytesNumber;
696  } else { /* Acknowledge was not detected. */
697  status = 0xFF;
698  }
699  if(stopBit) {
700  SPT0 = 1; /* Generate a stop condition. */
701  while(IICBSY0) ; /* Wait until the I2C bus status flag is cleared. */
702  }
703 
704  return status;
705 }