Embedded System Design 2 - Project
leuart.c
Go to the documentation of this file.
1 /***************************************************************************//**
2  * @file leuart.c
3  * @brief LEUART (serial communication) functionality required by the RN2483 LoRa modem.
4  * @version 2.0
5  * @author
6  * Guus Leenders@n
7  * Modified by Brecht Van Eeckhoudt
8  *
9  * ******************************************************************************
10  *
11  * @section Versions
12  *
13  * @li v1.0: DRAMCO GitHub version (https://github.com/DRAMCO/EFM32-RN2483-LoRa-Node).
14  * @li v1.1: Removed rtcdriver functionality (timeouts)
15  * @li v1.2: Added (basic) timeout functionality.
16  * @li v1.3: Refined timeout functionality and cleaned up unused things in comments.
17  * @li v2.0: Updated version number.
18  *
19  ******************************************************************************/
20 
21 /* ____ ____ _ __ __ ____ ___
22  * | _ \| _ \ / \ | \/ |/ ___/ _ \
23  * | | | | |_) | / _ \ | |\/| | | | | | |
24  * | |_| | _ < / ___ \| | | | |__| |_| |
25  * |____/|_| \_\/_/ \_\_| |_|\____\___/
26  * research group
27  * dramco.be/
28  *
29  * KU Leuven - Technology Campus Gent,
30  * Gebroeders De Smetstraat 1,
31  * B-9000 Gent, Belgium
32  *
33  * File: leuart.c
34  * Created: 2018-01-26
35  * Author: Guus Leenders - Modified by Brecht Van Eeckhoudt
36  *
37  * Description: This file contains the LEUART (serial communication)
38  * functionality required by the RN2483 LoRa modem.
39  */
40 
41 
42 #include <stdint.h> /* (u)intXX_t */
43 #include <stdbool.h> /* "bool", "true", "false" */
44 #include "em_device.h" /* Include necessary MCU-specific header file */
45 #include "em_chip.h" /* Chip Initialization */
46 #include "em_cmu.h" /* Clock management unit */
47 #include "em_gpio.h" /* General Purpose IO */
48 #include "em_leuart.h" /* Low Energy Universal Asynchronous Receiver/Transmitter Peripheral API */
49 #include "em_dma.h" /* Direct Memory Access (DMA) API */
50 #include "dmactrl.h" /* DMA driver */
51 
52 #include "leuart.h" /* Corresponding header file */
53 #include "delay.h" /* Delay functionality */
54 #include "pin_mapping.h" /* PORT and PIN definitions */
55 #include "debug_dbprint.h" /* Enable or disable printing to UART for debugging */
56 #include "util_string.h" /* Utility functionality regarding strings */
57 #include "util.h" /* Utility functionality */
58 
59 
60 /* Local definitions */
61 /** Enable (1) or disable (0) printing the timeout counter value using DBPRINT */
62 #define DBPRINT_TIMEOUT 0
63 
64 /* Maximum values for the counters before exiting a `while` loop */
65 #define TIMEOUT_SYNC 80
66 #define TIMEOUT_DMA 50000
67 #define TIMEOUT_SENDCMD 40000
68 #define TIMEOUT_WAITRESPONSE 2000000 /* Depends on spreading factor! */
69 
70 /* DMA Configurations */
71 #define DMA_CHANNEL_TX 0 /* DMA channel is 0 */
72 #define DMA_CHANNEL_RX 1
73 #define DMA_CHANNELS 2
74 
75 
76 /* Local variables */
77 static DMA_CB_TypeDef dmaCallBack[DMA_CHANNELS]; /* DMA callback structure */
79 volatile uint8_t bufferPointer = 0;
80 volatile bool receiveComplete = false;
81 
82 
84 {
85  memset(receiveBuffer, '\0', RECEIVE_BUFFER_SIZE);
86  receiveComplete = false;
87 }
88 
89 /* Static (internal) functions */
90 static void basicTxComplete(unsigned int channel, bool primary, void *user)
91 {
92  (void) user;
93  /* Refresh DMA basic transaction cycle */
94  DMA_ActivateBasic(DMA_CHANNEL_RX,
95  primary,
96  false,
97  (void *)&receiveBuffer[0],
98  (void *)&RN2483_UART->RXDATA,
99  0);
100  bufferPointer = 0;
101 }
102 
103 static void basicRxComplete(unsigned int channel, bool primary, void *user)
104 {
105  (void) user;
106 
107  /* Refresh DMA basic transaction cycle */
108  char c = RN2483_UART->RXDATA;
110  if(c != '\n'){
111  bufferPointer++;
112  DMA_ActivateBasic(DMA_CHANNEL_RX,
113  primary,
114  false,
116  NULL,
117  0);
118  }
119  else{
120  receiveComplete = true;
121  receiveBuffer[bufferPointer+1] = '\0';
122  }
123  }
124 }
125 
126 static bool Leuart_ResponseAvailable(void){
127  return (receiveComplete);
128 }
129 
130 void setupDma(void){
131  /* DMA configuration structs */
132  DMA_Init_TypeDef dmaInit;
133  DMA_CfgChannel_TypeDef rxChnlCfg;
134  DMA_CfgChannel_TypeDef txChnlCfg;
135  DMA_CfgDescr_TypeDef rxDescrCfg;
136  DMA_CfgDescr_TypeDef txDescrCfg;
137 
138  /* Initializing the DMA */
139  dmaInit.hprot = 0;
140  dmaInit.controlBlock = dmaControlBlock;
141  DMA_Init(&dmaInit);
142 
143  /* RX DMA setup*/
144  /* Set the interrupt callback routine */
146  /* Callback doesn't need userpointer */
147  dmaCallBack[DMA_CHANNEL_RX].userPtr = NULL;
148 
149  /* Setting up channel for TX*/
150  rxChnlCfg.highPri = false; /* Can't use with peripherals */
151  rxChnlCfg.enableInt = true; /* Enabling interrupt to refresh DMA cycle*/
152  /*Setting up DMA transfer trigger request*/
153  rxChnlCfg.select = DMAREQ_LEUART0_RXDATAV; /* DMAREQ_LEUART0_RXDATAV; */
154  /* Setting up callback function to refresh descriptors*/
155  rxChnlCfg.cb = &(dmaCallBack[DMA_CHANNEL_RX]);
156  DMA_CfgChannel(DMA_CHANNEL_RX, &rxChnlCfg);
157 
158  /* Setting up channel descriptor */
159  /* Destination is buffer, increment ourselves */
160  rxDescrCfg.dstInc = dmaDataIncNone;
161  /* Source is LEUART_RX register and transfers 8 bits each time */
162  rxDescrCfg.srcInc = dmaDataIncNone;
163  rxDescrCfg.size = dmaDataSize1;
164  /* Default setting of DMA arbitration*/
165  rxDescrCfg.arbRate = dmaArbitrate1;
166  rxDescrCfg.hprot = 0;
167  /* Configure primary descriptor */
168  DMA_CfgDescr(DMA_CHANNEL_RX, true, &rxDescrCfg);
169  DMA_CfgDescr(DMA_CHANNEL_RX, false, &rxDescrCfg);
170 
171  /* TX DMA setup*/
172  /* Set the interrupt callback routine */
174  /* Callback doesn't need userpointer */
175  dmaCallBack[DMA_CHANNEL_TX].userPtr = NULL;
176 
177  /* Setting up channel for TX*/
178  txChnlCfg.highPri = false; /* Can't use with peripherals */
179  txChnlCfg.enableInt = true; /* Enabling interrupt to refresh DMA cycle*/
180  /*Setting up DMA transfer trigger request*/
181  txChnlCfg.select = DMAREQ_LEUART0_TXBL; /* DMAREQ_LEUART0_RXDATAV; */
182  /* Setting up callback function to refresh descriptors*/
183  txChnlCfg.cb = &(dmaCallBack[DMA_CHANNEL_TX]);
184  DMA_CfgChannel(DMA_CHANNEL_TX, &txChnlCfg);
185 
186  /* Setting up channel descriptor */
187  /* Destination is LEUART_Tx register and doesn't move */
188  txDescrCfg.dstInc = dmaDataIncNone;
189  /* Source is LEUART_TX register and transfers 8 bits each time */
190  txDescrCfg.srcInc = dmaDataInc1;
191  txDescrCfg.size = dmaDataSize1;
192  /* Default setting of DMA arbitration*/
193  txDescrCfg.arbRate = dmaArbitrate1;
194  txDescrCfg.hprot = 0;
195  /* Configure primary descriptor */
196  DMA_CfgDescr(DMA_CHANNEL_TX, true, &txDescrCfg);
197 }
198 
199 static void sendLeuartData(char * buffer, uint8_t bufferLength)
200 {
201  /* Timeout counter */
202  uint32_t counter = 0;
203 
204  /* Wait for sync */
205  while ((counter < TIMEOUT_SYNC) && RN2483_UART->SYNCBUSY) counter++;
206 
207  /* Exit the function if the maximum waiting time was reached */
208  if (counter == TIMEOUT_SYNC)
209  {
210 
211 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
212  dbcrit("Waiting time for sync reached! (sendLeuartData)");
213 #endif /* DEBUG_DBPRINT */
214 
215  error(51);
216  }
217 #if DBPRINT_TIMEOUT == 1 /* DBPRINT_TIMEOUT */
218  else
219  {
220 
221 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
222  dbwarnInt("sendLeuartData SYNC (", counter, ")");
223 #endif /* DEBUG_DBPRINT */
224 
225  }
226 #endif /* DBPRINT_TIMEOUT */
227 
228  DMA_ActivateBasic(DMA_CHANNEL_TX,
229  true,
230  false,
231  (void *)&RN2483_UART->TXDATA,
232  buffer,
233  (unsigned int)(bufferLength - 1));
234 
235  /* Reset timeout counter */
236  counter = 0;
237 
238  /* Wait in EM1 for DMA channel enable */
239  while ((counter < TIMEOUT_DMA) && DMA_ChannelEnabled(DMA_CHANNEL_TX)) counter++;
240 
241  /* Exit the function if the maximum waiting time was reached */
242  if (counter == TIMEOUT_DMA)
243  {
244 
245 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
246  dbcrit("Waiting time for DMA channel enable reached! (sendLeuartData)");
247 #endif /* DEBUG_DBPRINT */
248 
249  error(52);
250  }
251 #if DBPRINT_TIMEOUT == 1 /* DBPRINT_TIMEOUT */
252  else
253  {
254 
255 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
256  dbwarnInt("sendLeuartData DMA (", counter, ")");
257 #endif /* DEBUG_DBPRINT */
258 
259  }
260 #endif /* DBPRINT_TIMEOUT */
261 
262 }
263 
264 static void setupLeuart(void)
265 {
266  /* Enable peripheral clocks */
267  CMU_ClockEnable(cmuClock_HFPER, true);
268  /* Configure GPIO pins */
269  CMU_ClockEnable(cmuClock_GPIO, true);
270  /* To avoid false start, configure output as high */
271  GPIO_PinModeSet(RN2483_TX_PORT, RN2483_TX_PIN, gpioModePushPull, 1);
272  GPIO_PinModeSet(RN2483_RX_PORT, RN2483_RX_PIN, gpioModeInput, 0);
273 
274  LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT; /* Default config is fine */
275  init.baudrate = 4800;
276 
277  /* Enable CORE LE clock in order to access LE modules */
278  CMU_ClockEnable(cmuClock_CORELE, true);
279 
280  /* Select LFRCO for LEUARTs (and wait for it to stabilize) */
281  CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);
282  CMU_ClockEnable(cmuClock_LEUART0, true);
283 
284  /* Do not prescale clock */
285  CMU_ClockDivSet(cmuClock_LEUART0, cmuClkDiv_1);
286 
287  /* Configure LEUART */
288  init.enable = leuartDisable;
289 
290  LEUART_Init(RN2483_UART, &init);
291 
292  /* Enable pins at default location */
293  RN2483_UART->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_TXPEN | RN2483_UART_LOC;
294 
295  /* Set RXDMAWU to wake up the DMA controller in EM2 */
296  LEUART_RxDmaInEM2Enable(RN2483_UART, true);
297 
298  /* Clear previous RX interrupts */
299  LEUART_IntClear(RN2483_UART, LEUART_IF_RXDATAV);
300  NVIC_ClearPendingIRQ(LEUART0_IRQn);
301 
302  /* Finally enable it */
303  LEUART_Enable(RN2483_UART, leuartEnable);
304 }
305 
306 void Leuart_Init(void)
307 {
308  // TODO: Lines below might fix some sleep functionality...
309  //CMU_ClockEnable(cmuClock_CORELE, true);
310  //CMU_ClockEnable(cmuClock_DMA, true);
311  //CMU_ClockEnable(cmuClock_LEUART0, true);
312 
313  setupDma();
315  setupLeuart();
316 
317  /* Auto baud setting */
318  char b[] = "U";
319  sendLeuartData(b, 1);
320  delay(500);
321 }
322 
323 void Leuart_Reinit(void)
324 {
325  // TODO: Lines below might fix some sleep functionality...
326  //CMU_ClockEnable(cmuClock_CORELE, true);
327  //CMU_ClockEnable(cmuClock_DMA, true);
328  //CMU_ClockEnable(cmuClock_LEUART0, true);
329 
330  LEUART_Reset(RN2483_UART);
332  setupLeuart();
333 
334  /* Auto baud setting */
335  char b[] = "U";
336  sendLeuartData(b, 1);
338  delay(20);
340 }
341 
343 {
344  GPIO_PinModeSet(RN2483_TX_PORT, RN2483_TX_PIN, gpioModePushPull, 1);
345  delay(40);
346  GPIO_PinModeSet(RN2483_TX_PORT, RN2483_TX_PIN, gpioModePushPull, 0);
347  delay(20);
348  GPIO_PinOutSet(RN2483_TX_PORT, RN2483_TX_PIN);
349 }
350 
351 void Leuart_ReadResponse(char * buffer, uint8_t bufferLength)
352 {
353  sprintf(buffer, "%s", receiveBuffer);
354  receiveComplete = false;
355  bufferPointer = 0;
356 }
357 
358 void Leuart_SendData(char * buffer, uint8_t bufferLength) /* TODO: Not used... */
359 {
360  /* Timeout counter */
361  uint32_t counter = 0;
362 
363  /* Send data over LEUART */
364  sendLeuartData(buffer, bufferLength);
365 
366  /* Wait for response */
367  while ((counter < TIMEOUT_WAITRESPONSE) && !Leuart_ResponseAvailable()) counter++;
368 
369  /* Exit the function if the maximum waiting time was reached */
370  if (counter == TIMEOUT_WAITRESPONSE)
371  {
372 
373 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
374  dbcrit("Waiting time for response reached! (Leuart_SendData)");
375 #endif /* DEBUG_DBPRINT */
376 
377  error(53);
378  }
379  else
380  {
381 
382 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
383  dbwarnInt("Leuart_SendData (", counter, ")");
384 #endif /* DEBUG_DBPRINT */
385 
386  }
387 
388  receiveComplete = true;
389 }
390 
391 /** Send a command string over the LEUART. "wakeUp" IS NOT USED */
392 Leuart_Status_t Leuart_SendCommand(char * cb, uint8_t cbl, volatile bool * wakeUp)
393 {
394  /* Timeout counter */
395  uint32_t counter = 0;
396 
397  /* Send data over LEUART */
398  sendLeuartData(cb, cbl);
399 
400  /* Wait for response */
401  while ((counter < TIMEOUT_SENDCMD) && !Leuart_ResponseAvailable()) counter++;
402 
403  /* Exit the function if the maximum waiting time was reached */
404  if (counter == TIMEOUT_SENDCMD)
405  {
406 
407 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
408  dbcrit("Waiting time for response reached! (Leuart_SendCommand)");
409 #endif /* DEBUG_DBPRINT */
410 
411  error(54);
412 
413  return (TX_TIMEOUT);
414  }
415 #if DBPRINT_TIMEOUT == 1 /* DBPRINT_TIMEOUT */
416  else
417  {
418 
419 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
420  dbwarnInt("Leuart_SendCommand (", counter, ")");
421 #endif /* DEBUG_DBPRINT */
422 
423  }
424 #endif /* DBPRINT_TIMEOUT */
425 
426  return (DATA_SENT);
427 }
428 
429 
431 {
432  /* Timeout counter */
433  uint32_t counter = 0;
434 
435  /* Activate DMA */
436  DMA_ActivateBasic( DMA_CHANNEL_RX,
437  true,
438  false,
439  (void *)&receiveBuffer[0],
440  (void *)&RN2483_UART->RXDATA,
441  0);
442 
443  /* Wait for response */
444  while ((counter < TIMEOUT_WAITRESPONSE) && !Leuart_ResponseAvailable()) counter++;
445 
446  /* Exit the function if the maximum waiting time was reached */
447  if (counter == TIMEOUT_WAITRESPONSE)
448  {
449 
450 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
451  dbcrit("Waiting time for response reached! (Leuart_WaitForResponse)");
452 #endif /* DEBUG_DBPRINT */
453 
454  error(55);
455 
456  return (RX_TIMEOUT);
457  }
458 #if DBPRINT_TIMEOUT == 1 /* DBPRINT_TIMEOUT */
459  else
460  {
461 
462 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
463  dbwarnInt("Leuart_WaitForResponse (", counter, ")");
464 #endif /* DEBUG_DBPRINT */
465 
466  }
467 #endif /* DBPRINT_TIMEOUT */
468 
469  return (DATA_RECEIVED);
470 }
471 
enum leuart_statuses Leuart_Status_t
#define TIMEOUT_DMA
Definition: leuart.c:66
void Leuart_Reinit(void)
Definition: leuart.c:323
void Leuart_SendData(char *buffer, uint8_t bufferLength)
Definition: leuart.c:358
Leuart_Status_t Leuart_SendCommand(char *cb, uint8_t cbl, volatile bool *wakeUp)
Definition: leuart.c:392
void Leuart_Init(void)
Definition: leuart.c:306
#define TIMEOUT_SYNC
Definition: leuart.c:65
#define RN2483_UART_LOC
Definition: pin_mapping.h:116
Leuart_Status_t Leuart_WaitForResponse()
Definition: leuart.c:430
#define RN2483_UART
Definition: pin_mapping.h:115
void dbwarnInt(char *message1, int32_t value, char *message2)
Print a warning value surrounded by two strings (char array) to USARTx.
Definition: dbprint.c:598
#define RN2483_TX_PIN
Definition: pin_mapping.h:118
void Leuart_BreakCondition(void)
Definition: leuart.c:342
#define TIMEOUT_WAITRESPONSE
Definition: leuart.c:68
#define DMA_CHANNEL_RX
Definition: leuart.c:72
static bool Leuart_ResponseAvailable(void)
Definition: leuart.c:126
static void sendLeuartData(char *buffer, uint8_t bufferLength)
Definition: leuart.c:199
#define RN2483_RX_PORT
Definition: pin_mapping.h:119
#define RN2483_TX_PORT
Definition: pin_mapping.h:117
static void setupLeuart(void)
Definition: leuart.c:264
#define DMA_CHANNELS
Definition: leuart.c:73
ADC_Init_TypeDef init
Definition: adc.c:71
void error(uint8_t number)
Error method.
Definition: util.c:131
#define TIMEOUT_SENDCMD
Definition: leuart.c:67
#define RN2483_RX_PIN
Definition: pin_mapping.h:120
Utility functionality.
void setupDma(void)
Definition: leuart.c:130
The pin definitions for the regular and custom Happy Gecko board.
#define DMA_CHANNEL_TX
Definition: leuart.c:71
static void basicTxComplete(unsigned int channel, bool primary, void *user)
Definition: leuart.c:90
Delay functionality.
Enable or disable printing to UART with dbprint.
void delay(uint32_t msDelay)
Wait for a certain amount of milliseconds in EM2/3.
Definition: delay.c:124
#define RECEIVE_BUFFER_SIZE
Definition: leuart.h:23
void Leuart_ClearBuffers(void)
Definition: leuart.c:83
static DMA_CB_TypeDef dmaCallBack[2]
Definition: leuart.c:77
volatile bool receiveComplete
Definition: leuart.c:80
void Leuart_ReadResponse(char *buffer, uint8_t bufferLength)
Definition: leuart.c:351
void dbcrit(char *message)
Print a critical error string (char array) in red to USARTx and go to the next line.
Definition: dbprint.c:539
char receiveBuffer[50]
Definition: leuart.c:78
static void basicRxComplete(unsigned int channel, bool primary, void *user)
Definition: leuart.c:103
volatile uint8_t bufferPointer
Definition: leuart.c:79