Guest User

NRF52840 UARTE driver

a guest
Apr 28th, 2020
276
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 33.00 KB | None | 0 0
  1. /*
  2.  * Copyright 2020 u-blox Cambourne Ltd
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.     http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16.  
  17. #ifdef CELLULAR_CFG_OVERRIDE
  18. # include "cellular_cfg_override.h" // For a customer's configuration override
  19. #endif
  20. #include "cellular_cfg_sw.h"
  21. #include "cellular_port_debug.h"
  22. #include "cellular_port_clib.h"
  23. #include "cellular_port.h"
  24. #include "cellular_port_os.h"
  25. #include "cellular_port_uart.h"
  26. #include "cellular_port_private.h"
  27.  
  28. #include "FreeRTOS.h"
  29. #include "queue.h"
  30. #include "task.h"
  31.  
  32. #include "nrf.h"
  33. #include "nrf_uarte.h"
  34. #include "nrf_gpio.h"
  35.  
  36. /* Note: in order to implement the API we require, where receipt
  37.  * of data is signalled by an event queue and other things can
  38.  * send to that same event queue, this code is implemented on top of
  39.  * the nrf_uarte.h HAL and replaces the nrfx_uarte.h default driver
  40.  * from Nordic.  It steals from the code in nrfx_uarte.c, Nordic's
  41.  * implementation.
  42.  *
  43.  * So that users can continue to use the Nordic UARTE driver this
  44.  * code uses only the UART port that the Nordic UARTE driver is NOT
  45.  * using: for instance, to use UARTE1 in this driver then
  46.  * NRFX_UARTE1_ENABLED should be set to 0 in sdk_config to free it
  47.  * up.
  48.  *
  49.  * Design note: at first this code used DMA plus a per-character
  50.  * interrupt to count the characters and send an event when the
  51.  * number unread transitioned from 0 to 1 but the load of sending the
  52.  * event was too high and interrupts were missed, leading to losing
  53.  * count. So the timer already in use for cellularPortGetTickTimeMs()
  54.  * was modified to generate interrupts more quickly (130 ms interval)
  55.  * when the UART is operating and take a callback which could be
  56.  * used to stop the free-running DMA and query it for the number
  57.  * of characters received.  This worked well except that it was
  58.  * still pouring characters directly into the destination buffer
  59.  * and this caused a problem towards the end of the buffer where
  60.  * the space for DMA would be getting close to zero and the load of
  61.  * setup etc. for the next DMA became too much.  So instead the
  62.  * buffer space was split into separately managed sub-buffers, at
  63.  * least two in number, and then advantage could be taken of the
  64.  * hardware's ability to set up a second buffer in advance
  65.  * of the first completing ('cos the buffer pointer register is
  66.  * itself buffered).  Finally, no character loss, though some buffer
  67.  * management is required at setup and when reading the data out again.
  68.  */
  69.  
  70. /* ----------------------------------------------------------------
  71.  * COMPILE-TIME MACROS
  72.  * -------------------------------------------------------------- */
  73.  
  74. // The maximum number of UARTs supported, which is the range of the
  75. // "uart" parameter on this platform
  76. #ifndef NRFX_UARTE_ENABLED
  77. // NRFX_UARTE is not enabled, we can have both
  78. # define CELLULAR_PORT_UART_MAX_NUM 2
  79. #else
  80. # if !NRFX_UARTE0_ENABLED && !NRFX_UARTE1_ENABLED
  81. // NRFX_UARTE is enabled but neither UARTEx is enabled so we can
  82. // have both
  83. #  define CELLULAR_PORT_UART_MAX_NUM 2
  84. # else
  85. #  if !NRFX_UARTE0_ENABLED || !NRFX_UARTE1_ENABLED
  86. #    define CELLULAR_PORT_UART_MAX_NUM 1
  87. #  else
  88. #    error No UARTs available, both are being used by the Nordic NRFX_UARTE driver; to use this code at least one of NRFX_UARTE0_ENABLED or NRFX_UARTE1_ENABLED must be set to 0.
  89. #  endif
  90. # endif
  91. #endif
  92.  
  93. // Maximum length of DMA on NRF52840 HW.
  94. #ifndef CELLULAR_PORT_UART_SUB_BUFFER_SIZE
  95. # define CELLULAR_PORT_UART_SUB_BUFFER_SIZE 256
  96. #endif
  97.  
  98. // The number of sub-buffers.
  99. // We want at least two buffers and beyond that a number of buffers
  100. // that brings the size of each under the maximum DMA length.
  101. // IMPORTANT: this means that for this platform it is best if
  102. // CELLULAR_PORT_UART_RX_BUFFER_SIZE is a multiple of 256,
  103. // which it is with the default of 1024.
  104. #define CELLULAR_PORT_UART_NUM_SUB_BUFFERS (CELLULAR_PORT_UART_RX_BUFFER_SIZE / CELLULAR_PORT_UART_SUB_BUFFER_SIZE)
  105.  
  106. #if CELLULAR_PORT_UART_NUM_SUB_BUFFERS < 2
  107. # error Cannot accommodate even two sub-buffers, either increase CELLULAR_PORT_UART_RX_BUFFER_SIZE to a larger multiple of CELLULAR_PORT_UART_SUB_BUFFER_SIZE or reduce CELLULAR_PORT_UART_SUB_BUFFER_SIZE.
  108. #endif
  109.  
  110. /* ----------------------------------------------------------------
  111.  * TYPES
  112.  * -------------------------------------------------------------- */
  113.  
  114. /** Structure to hold a UART event.
  115.  */
  116. typedef struct {
  117.     int32_t type;
  118.     size_t size;
  119. } CellularPortUartEventData_t;
  120.  
  121. /** UART buffer structure, which can be used as a list.
  122.  */
  123. typedef struct CellularPortUartBuffer_t {
  124.     char *pStart;
  125.     char *pRead;
  126.     volatile size_t toRead;
  127.     struct CellularPortUartBuffer_t *pNext;
  128. } CellularPortUartBuffer_t;
  129.  
  130. /** Structure of the things we need to keep track of per UART.
  131.  */
  132. typedef struct {
  133.     NRF_UARTE_Type *pReg;
  134.     CellularPortMutexHandle_t mutex;
  135.     CellularPortQueueHandle_t queue;
  136.     CellularPortUartBuffer_t *pRxBufferRead;
  137.     volatile CellularPortUartBuffer_t *pRxBufferWrite;
  138.     volatile CellularPortUartBuffer_t *pRxBufferWriteNext;
  139.     bool userNeedsNotify; //!< set this if toRead has hit zero and
  140.                           // hence the user would like a notification
  141.                           // when new data arrives.
  142.     CellularPortUartBuffer_t rxBufferList[CELLULAR_PORT_UART_NUM_SUB_BUFFERS];
  143. } CellularPortUartData_t;
  144.  
  145. /* ----------------------------------------------------------------
  146.  * VARIABLES
  147.  * -------------------------------------------------------------- */
  148.  
  149. // UART data, where the UARTE register is the only one initialised here.
  150. #if !NRFX_UARTE0_ENABLED && !NRFX_UARTE1_ENABLED
  151. static CellularPortUartData_t gUartData[] = {{NRF_UARTE0, },
  152.                                              {NRF_UARTE1, }};
  153. # else
  154. #  if !NRFX_UARTE0_ENABLED
  155. static CellularPortUartData_t gUartData[] = {NRF_UARTE0, };
  156. #  else
  157. static CellularPortUartData_t gUartData[] = {NRF_UARTE1, };
  158. #  endif
  159. #endif
  160.  
  161. /* ----------------------------------------------------------------
  162.  * STATIC FUNCTIONS
  163.  * -------------------------------------------------------------- */
  164.  
  165. // Callback to be called when the receive check timer has expired.
  166. // pParameter must be a pointer to CellularPortUartData_t.
  167. static void rxCb(void *pParameter)
  168. {
  169.     CellularPortUartData_t *pUartData = (CellularPortUartData_t *) pParameter;
  170.  
  171.     nrf_uarte_task_trigger(pUartData->pReg,
  172.                            NRF_UARTE_TASK_STOPRX);
  173. }
  174.  
  175. // The interrupt handler: only handles Rx events as Tx is blocking.
  176. static void rxIrqHandler(CellularPortUartData_t *pUartData)
  177. {
  178.     NRF_UARTE_Type *pReg = pUartData->pReg;
  179.     BaseType_t yield = false;
  180.  
  181.     if (nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_ENDRX)) {
  182.         volatile CellularPortUartBuffer_t *pRxBuffer;
  183.         size_t x;
  184.         // Clear the event
  185.         nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ENDRX);
  186.         // Grab the count of the number of bytes DMAed
  187.         x = nrf_uarte_rx_amount_get(pReg);
  188.         // The ENDRX event is shorted across to the STARTRX event
  189.         // in order not to lose any data, so it may already
  190.         // have begun pouring data into the next buffer.
  191.         // Remember where we are and move the current receive
  192.         // write buffer on.
  193.         pRxBuffer = pUartData->pRxBufferWrite;
  194.         pUartData->pRxBufferWrite = pUartData->pRxBufferWrite->pNext;
  195.         // Now update the read count
  196.         pRxBuffer->toRead = x;
  197.         // If there is at least some data and the user needs to
  198.         // be notified, let them know
  199.         if ((pRxBuffer->toRead > 0) && pUartData->userNeedsNotify) {
  200.             CellularPortUartEventData_t uartEvent;
  201.             uartEvent.type = 0;
  202.             uartEvent.size = pRxBuffer->toRead;
  203.             xQueueSendFromISR((QueueHandle_t *) (pUartData->queue),
  204.                               &uartEvent, &yield);
  205.             pUartData->userNeedsNotify = false;
  206.         }
  207.     } else if (nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_RXSTARTED)) {
  208.         // An RX has started so it's OK to update the buffer
  209.         // pointer registers in the hardware for the one that
  210.         // will follow after this one has ended as the
  211.         // Rx buffer register is double-buffered in HW.
  212.         nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_RXSTARTED);
  213.         nrf_uarte_rx_buffer_set(pReg,
  214.                                 (uint8_t *) (pUartData->pRxBufferWriteNext->pStart),
  215.                                 CELLULAR_PORT_UART_SUB_BUFFER_SIZE);
  216.         pUartData->pRxBufferWriteNext = pUartData->pRxBufferWriteNext->pNext;
  217.     } else if (nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_RXTO)) {
  218.         // We've been stopped, must have been a timeout.
  219.         // ENDRX will already have been sent and that
  220.         // is shorted across to STARTRX so no need to do
  221.         // anything here.
  222.         nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_RXTO);
  223.     } else if (nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_ERROR)) {
  224.         // Clear any errors: no need to do anything, they
  225.         // have no effect upon reception
  226.         nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ERROR);
  227.         nrf_uarte_errorsrc_get_and_clear(pReg);
  228.     }
  229.  
  230.     // Required for FreeRTOS task scheduling to work
  231.     if (yield) {
  232.         taskYIELD();
  233.     }
  234. }
  235.  
  236. // Convert a baud rate into an NRF52840 baud rate.
  237. static int32_t baudRateToNrfBaudRate(int32_t baudRate)
  238. {
  239.     int32_t baudRateNrf = -1;
  240.  
  241.     switch (baudRate) {
  242.         case 1200:
  243.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud1200;
  244.         break;
  245.         case 2400:
  246.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud2400;
  247.         break;
  248.         case 9600:
  249.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud9600;
  250.         break;
  251.         case 14400:
  252.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud14400;
  253.         break;
  254.         case 19200:
  255.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud19200;
  256.         break;
  257.         case 28800:
  258.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud28800;
  259.         break;
  260.         case 31250:
  261.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud31250;
  262.         break;
  263.         case 38400:
  264.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud38400;
  265.         break;
  266.         case 56000:
  267.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud56000;
  268.         break;
  269.         case 57600:
  270.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud57600;
  271.         break;
  272.         case 76800:
  273.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud76800;
  274.         break;
  275.         case 115200:
  276.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud115200;
  277.         break;
  278.         case 230400:
  279.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud230400;
  280.         break;
  281.         case 250000:
  282.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud250000;
  283.         break;
  284.         case 460800:
  285.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud460800;
  286.         break;
  287.         case 921600:
  288.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud921600;
  289.         break;
  290.         case 1000000:
  291.             baudRateNrf = UARTE_BAUDRATE_BAUDRATE_Baud1M;
  292.         break;
  293.         default:
  294.         break;
  295.     }
  296.  
  297.     return baudRateNrf;
  298. }
  299.  
  300. // Derived from the NRFX functions nrfx_is_in_ram() and
  301. // nrfx_is_word_aligned(), check if a buffer pointer is good
  302. // for DMA
  303. __STATIC_INLINE bool isGoodForDma(void const *pBuffer)
  304. {
  305.     return (((((uint32_t) pBuffer) & 0x3u) == 0u) &&
  306.             ((((uint32_t) pBuffer) & 0xE0000000u) == 0x20000000u));
  307. }
  308.  
  309. // Derived from the NRFX function nrfx_get_irq_number()
  310. __STATIC_INLINE IRQn_Type getIrqNumber(void const *pReg)
  311. {
  312.     return (IRQn_Type) (uint8_t)((uint32_t)(pReg) >> 12);
  313. }
  314.  
  315. /* ----------------------------------------------------------------
  316.  * PUBLIC FUNCTIONS: INTERRUPT HANDLERS
  317.  * -------------------------------------------------------------- */
  318.  
  319. #if !NRFX_UARTE0_ENABLED
  320. void nrfx_uarte_0_irq_handler(void)
  321. {
  322.     rxIrqHandler(&(gUartData[0]));
  323. }
  324. #endif
  325.  
  326. #if !NRFX_UARTE1_ENABLED
  327. void nrfx_uarte_1_irq_handler(void)
  328. {
  329.     rxIrqHandler(&(gUartData[1]));
  330. }
  331. #endif
  332.  
  333. /* ----------------------------------------------------------------
  334.  * PUBLIC FUNCTIONS
  335.  * -------------------------------------------------------------- */
  336.  
  337. // Initialise a UARTE.
  338. int32_t cellularPortUartInit(int32_t pinTx, int32_t pinRx,
  339.                              int32_t pinCts, int32_t pinRts,
  340.                              int32_t baudRate,
  341.                              size_t rtsThreshold,
  342.                              int32_t uart,
  343.                              CellularPortQueueHandle_t *pUartQueue)
  344. {
  345.     CellularPortErrorCode_t errorCode = CELLULAR_PORT_INVALID_PARAMETER;
  346.     int32_t baudRateNrf = baudRateToNrfBaudRate(baudRate);
  347.     uint32_t pinCtsNrf = NRF_UARTE_PSEL_DISCONNECTED;
  348.     uint32_t pinRtsNrf = NRF_UARTE_PSEL_DISCONNECTED;
  349.     nrf_uarte_hwfc_t hwfc = NRF_UARTE_HWFC_DISABLED;
  350.     NRF_UARTE_Type *pReg;
  351.     char *pRxBuffer = NULL;
  352.  
  353.     // TODO: use this
  354.     (void) rtsThreshold;
  355.  
  356.     if ((pUartQueue != NULL) && (pinRx >= 0) && (pinTx >= 0) &&
  357.         (uart < sizeof(gUartData) / sizeof(gUartData[0])) &&
  358.         (baudRateNrf >= 0)) {
  359.         errorCode = CELLULAR_PORT_SUCCESS;
  360.         if (gUartData[uart].mutex == NULL) {
  361.             pReg = gUartData[uart].pReg;
  362.  
  363. #if NRFX_PRS_ENABLED
  364.             static nrfx_irq_handler_t const irq_handlers[NRFX_UARTE_ENABLED_COUNT] = {
  365. # if !NRFX_UARTE0_ENABLED
  366.                 nrfx_uarte_0_irq_handler,
  367. # endif
  368. # if !NRFX_UARTE1_ENABLED
  369.                 nrfx_uarte_1_irq_handler,
  370. # endif
  371.             };
  372.             if (nrfx_prs_acquire(pReg, irq_handlers[pReg) != NRFX_SUCCESS) {
  373.                 errorCode = CELLULAR_PORT_PLATFORM_ERROR;
  374.             }
  375. #endif
  376.             if (errorCode == 0) {
  377.                 // Create the mutex
  378.                 errorCode = cellularPortMutexCreate(&(gUartData[uart].mutex));
  379.                 if (errorCode == 0) {
  380.  
  381.                     CELLULAR_PORT_MUTEX_LOCK(gUartData[uart].mutex);
  382.  
  383.                     errorCode = CELLULAR_PORT_OUT_OF_MEMORY;
  384.  
  385.                     // Malloc memory for the read buffer
  386.                     pRxBuffer = pCellularPort_malloc(CELLULAR_PORT_UART_RX_BUFFER_SIZE);
  387.                     if (pRxBuffer != NULL) {
  388.                         // Set up the buffer list
  389.                         for (size_t x = 0; x < sizeof(gUartData[uart].rxBufferList) /
  390.                                                sizeof(gUartData[uart].rxBufferList[0]); x++) {
  391.                             gUartData[uart].rxBufferList[x].pStart = pRxBuffer;
  392.                             gUartData[uart].rxBufferList[x].pRead = pRxBuffer;
  393.                             gUartData[uart].rxBufferList[x].toRead = 0;
  394.                             // Set up the next pointers in a ring
  395.                             if (x < sizeof(gUartData[uart].rxBufferList) /
  396.                                     sizeof(gUartData[uart].rxBufferList[0]) - 1) {
  397.                                 gUartData[uart].rxBufferList[x].pNext = &(gUartData[uart].rxBufferList[x + 1]);
  398.                             } else {
  399.                                 gUartData[uart].rxBufferList[x].pNext = &(gUartData[uart].rxBufferList[0]);
  400.                             }
  401.                             cellularPortLog("x %d: gUartData[uart].rxBufferList[x].pNext 0x%08x.\n", x, (int) gUartData[uart].rxBufferList[x].pNext);
  402.                             pRxBuffer += CELLULAR_PORT_UART_SUB_BUFFER_SIZE;
  403.                         }
  404.                         gUartData[uart].pRxBufferRead = &(gUartData[uart].rxBufferList[0]);
  405.                         gUartData[uart].pRxBufferWrite = &(gUartData[uart].rxBufferList[0]);
  406.                         gUartData[uart].pRxBufferWriteNext = gUartData[uart].pRxBufferWrite->pNext;
  407.                         gUartData[uart].userNeedsNotify = true;
  408.  
  409.                         // Create the queue
  410.                         errorCode = cellularPortQueueCreate(CELLULAR_PORT_UART_EVENT_QUEUE_SIZE,
  411.                                                             sizeof(CellularPortUartEventData_t),
  412.                                                             pUartQueue);
  413.                         if (errorCode == 0) {
  414.                             gUartData[uart].queue = *pUartQueue;
  415.  
  416.                             // Set baud rate
  417.                             nrf_uarte_baudrate_set(pReg, baudRateNrf);
  418.  
  419.                             // Set Tx/Rx pins
  420.                             nrf_gpio_pin_set(pinTx);
  421.                             nrf_gpio_cfg_output(pinTx);
  422.                             // You might expect this to be "no pull" since
  423.                             // the line is pulled up by the module already but
  424.                             // the problem is that when the module is powered
  425.                             // off the pin floats low which the NRF52840 UART
  426.                             // reads as "break" which floods the input buffers
  427.                             // with a constant 0 that its impossible to switch
  428.                             // off.
  429.                             nrf_gpio_cfg_input(pinRx, NRF_GPIO_PIN_PULLUP);
  430.                             nrf_uarte_txrx_pins_set(pReg, pinTx, pinRx);
  431.  
  432.                             // Set flow control
  433.                             if (pinCts >= 0) {
  434.                                 pinCtsNrf = pinCts;
  435.                                 nrf_gpio_cfg_input(pinCtsNrf,
  436.                                                    NRF_GPIO_PIN_NOPULL);
  437.                                 hwfc = NRF_UARTE_HWFC_ENABLED;
  438.                             }
  439.                             if (pinRts >= 0) {
  440.                                 pinRtsNrf = pinRts;
  441.                                 nrf_gpio_pin_set(pinRtsNrf);
  442.                                 nrf_gpio_cfg_output(pinRtsNrf);
  443.                                 hwfc = NRF_UARTE_HWFC_ENABLED;
  444.                             }
  445.  
  446.                             if (hwfc == NRF_UARTE_HWFC_ENABLED) {
  447.                                 nrf_uarte_hwfc_pins_set(pReg, pinRtsNrf, pinCtsNrf);
  448.                             }
  449.  
  450.                             // Configure the UART
  451.                             nrf_uarte_configure(pReg, NRF_UARTE_PARITY_EXCLUDED, hwfc);
  452.  
  453.                            // Enable the UART
  454.                             nrf_uarte_enable(pReg);
  455.  
  456.                             // Clear flags, set Rx interrupt and buffer and let it go
  457.                             nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ENDRX);
  458.                             nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ENDTX);
  459.                             nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ERROR);
  460.                             nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_RXTO);
  461.                             nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_RXSTARTED);
  462.                             nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_TXSTOPPED);
  463.  
  464.                             // Let the end of one RX trigger the next immediately
  465.                             nrf_uarte_shorts_enable(pReg, NRF_UARTE_SHORT_ENDRX_STARTRX);
  466.  
  467.                             nrf_uarte_rx_buffer_set(pReg,
  468.                                                     (uint8_t *) (gUartData[uart].pRxBufferWrite->pStart),
  469.                                                     CELLULAR_PORT_UART_SUB_BUFFER_SIZE);
  470.                             nrf_uarte_task_trigger(pReg, NRF_UARTE_TASK_STARTRX);
  471.                             nrf_uarte_int_enable(pReg, NRF_UARTE_INT_ENDRX_MASK     |
  472.                                                        NRF_UARTE_INT_ERROR_MASK     |
  473.                                                        NRF_UARTE_INT_RXTO_MASK      |
  474.                                                        NRF_UARTE_INT_RXSTARTED_MASK);
  475.                             NRFX_IRQ_PRIORITY_SET(getIrqNumber((void *) pReg),
  476.                                                   NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY);
  477.                             NRFX_IRQ_ENABLE(getIrqNumber((void *) (pReg)));
  478.  
  479.                             // Put the tick timer into UART mode and
  480.                             // register the receive timout callback
  481.                             cellularPortPrivateTickTimeUartMode();
  482.                             cellularPortPrivateTickTimeSetInterruptCb(rxCb,
  483.                                                                       &(gUartData[uart]));
  484.                         }
  485.                     }
  486.  
  487.                     CELLULAR_PORT_MUTEX_UNLOCK(gUartData[uart].mutex);
  488.  
  489.                     // If we failed to create the queue or get memory for the buffer,
  490.                     // delete the mutex, free memory and put the uart's
  491.                     // mutex back to NULL
  492.                     if ((errorCode != 0) ||
  493.                         (pRxBuffer == NULL)) {
  494.                         cellularPortMutexDelete(gUartData[uart].mutex);
  495.                         gUartData[uart].mutex = NULL;
  496.                         cellularPort_free(pRxBuffer);
  497.                     }
  498.                 }
  499.             }
  500.         }
  501.     }
  502.  
  503.     return (int32_t) errorCode;
  504. }
  505.  
  506. // Shutdown a UART.
  507. int32_t cellularPortUartDeinit(int32_t uart)
  508. {
  509.     CellularPortErrorCode_t errorCode = CELLULAR_PORT_INVALID_PARAMETER;
  510.     uint32_t pinRtsNrf;
  511.     uint32_t pinCtsNrf;
  512.     NRF_UARTE_Type *pReg;
  513.  
  514.     if (uart < sizeof(gUartData) / sizeof(gUartData[0])) {
  515.         errorCode = CELLULAR_PORT_SUCCESS;
  516.         if (gUartData[uart].mutex != NULL) {
  517.             errorCode = CELLULAR_PORT_PLATFORM_ERROR;
  518.             pReg = gUartData[uart].pReg;
  519.  
  520.             // This function should not be called if another task
  521.             // already has the mutex, do a quick check here
  522.             cellularPort_assert(cellularPortMutexGetLocker(gUartData[uart].mutex) == NULL);
  523.  
  524.             // No need to lock the mutex, we need to delete it
  525.             // and we're not allowed to delete a locked mutex.
  526.             // The caller needs to make sure that no read/write
  527.             // is in progress when this function is called.
  528.  
  529.             // Disable Rx interrupts
  530.             nrf_uarte_int_disable(pReg, NRF_UARTE_INT_ENDRX_MASK     |
  531.                                         NRF_UARTE_INT_ERROR_MASK     |
  532.                                         NRF_UARTE_INT_RXTO_MASK      |
  533.                                         NRF_UARTE_INT_RXSTARTED_MASK);
  534.             NRFX_IRQ_DISABLE(nrfx_get_irq_number((void *) (pReg)));
  535.  
  536.             // Deregister the timer callback and
  537.             // return the tick timer to normal mode
  538.             cellularPortPrivateTickTimeSetInterruptCb(NULL, NULL);
  539.             cellularPortPrivateTickTimeNormalMode();
  540.  
  541.             // Make sure all transfers are finished before UARTE is
  542.             // disabled to achieve the lowest power consumption
  543.             nrf_uarte_shorts_disable(pReg, NRF_UARTE_SHORT_ENDRX_STARTRX);
  544.             nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_RXTO);
  545.             nrf_uarte_task_trigger(pReg, NRF_UARTE_TASK_STOPRX);
  546.             nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_TXSTOPPED);
  547.             nrf_uarte_task_trigger(pReg, NRF_UARTE_TASK_STOPTX);
  548.             while (!nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_TXSTOPPED) ||
  549.                    !nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_RXTO)) {}
  550.  
  551.             // Disable the UARTE
  552.             nrf_uarte_disable(pReg);
  553.  
  554.             // Put the pins back
  555.             nrf_gpio_cfg_default(nrf_uarte_tx_pin_get(pReg));
  556.             nrf_gpio_cfg_default(nrf_uarte_rx_pin_get(pReg));
  557.             nrf_uarte_txrx_pins_disconnect(pReg);
  558.             pinRtsNrf = nrf_uarte_rts_pin_get(pReg);
  559.             pinCtsNrf = nrf_uarte_cts_pin_get(pReg);
  560.             nrf_uarte_hwfc_pins_disconnect(pReg);
  561.             if (pinCtsNrf != NRF_UARTE_PSEL_DISCONNECTED) {
  562.                 nrf_gpio_cfg_default(pinCtsNrf);
  563.             }
  564.             if (pinRtsNrf != NRF_UARTE_PSEL_DISCONNECTED) {
  565.                 nrf_gpio_cfg_default(pinRtsNrf);
  566.             }
  567.  
  568.             // Delete the queue
  569.             cellularPortQueueDelete(gUartData[uart].queue);
  570.             gUartData[uart].queue = NULL;
  571.             // Free the buffer
  572.             cellularPort_free(gUartData[uart].rxBufferList[0].pStart);
  573.             // Delete the mutex
  574.             cellularPortMutexDelete(gUartData[uart].mutex);
  575.             gUartData[uart].mutex = NULL;
  576.             errorCode = CELLULAR_PORT_SUCCESS;
  577.         }
  578.     }
  579.  
  580.     return (int32_t) errorCode;
  581. }
  582.  
  583. // Push a UART event onto the UART event queue.
  584. int32_t cellularPortUartEventSend(const CellularPortQueueHandle_t queueHandle,
  585.                                   int32_t sizeBytes)
  586. {
  587.     int32_t errorCode = CELLULAR_PORT_INVALID_PARAMETER;
  588.     CellularPortUartEventData_t uartEvent;
  589.  
  590.     if (queueHandle != NULL) {
  591.         uartEvent.type = -1;
  592.         uartEvent.size = 0;
  593.         if (sizeBytes >= 0) {
  594.             uartEvent.type = 0;
  595.             uartEvent.size = sizeBytes;
  596.         }
  597.         errorCode = cellularPortQueueSend(queueHandle, (void *) &uartEvent);
  598.     }
  599.  
  600.     return errorCode;
  601. }
  602.  
  603. // Receive a UART event, blocking until one turns up.
  604. int32_t cellularPortUartEventReceive(const CellularPortQueueHandle_t queueHandle)
  605. {
  606.     int32_t sizeOrErrorCode = CELLULAR_PORT_INVALID_PARAMETER;
  607.     CellularPortUartEventData_t uartEvent;
  608.  
  609.     if (queueHandle != NULL) {
  610.         sizeOrErrorCode = CELLULAR_PORT_PLATFORM_ERROR;
  611.         if (cellularPortQueueReceive(queueHandle, &uartEvent) == 0) {
  612.             sizeOrErrorCode = CELLULAR_PORT_UNKNOWN_ERROR;
  613.             if (uartEvent.type >= 0) {
  614.                 sizeOrErrorCode = uartEvent.size;
  615.             }
  616.         }
  617.     }
  618.  
  619.     return sizeOrErrorCode;
  620. }
  621.  
  622. // Get the number of bytes waiting in the receive buffer.
  623. int32_t cellularPortUartGetReceiveSize(int32_t uart)
  624. {
  625.     CellularPortErrorCode_t sizeOrErrorCode = CELLULAR_PORT_INVALID_PARAMETER;
  626.     CellularPortUartBuffer_t *pRxBuffer;
  627.  
  628.     if (uart < sizeof(gUartData) / sizeof(gUartData[0])) {
  629.         sizeOrErrorCode = CELLULAR_PORT_NOT_INITIALISED;
  630.         if (gUartData[uart].mutex != NULL) {
  631.  
  632.             CELLULAR_PORT_MUTEX_LOCK(gUartData[uart].mutex);
  633.  
  634.             // Count up the lot
  635.             pRxBuffer = gUartData[uart].pRxBufferRead;
  636.             sizeOrErrorCode = 0;
  637.             for (size_t x = 0; x < sizeof(gUartData[uart].rxBufferList) /
  638.                                    sizeof(gUartData[uart].rxBufferList[0]); x++) {
  639.                 sizeOrErrorCode += pRxBuffer->toRead;
  640.                 pRxBuffer = pRxBuffer->pNext;
  641.             }
  642.  
  643.             CELLULAR_PORT_MUTEX_UNLOCK(gUartData[uart].mutex);
  644.  
  645.         }
  646.     }
  647.  
  648.     return (int32_t) sizeOrErrorCode;
  649. }
  650.  
  651. // Read from the given UART interface.
  652. int32_t cellularPortUartRead(int32_t uart, char *pBuffer,
  653.                              size_t sizeBytes)
  654. {
  655.     CellularPortErrorCode_t sizeOrErrorCode = CELLULAR_PORT_INVALID_PARAMETER;
  656.     CellularPortUartBuffer_t *pRxBuffer;
  657.     size_t thisRead;
  658.  
  659.     if ((pBuffer != NULL) && (sizeBytes > 0) &&
  660.         (uart < sizeof(gUartData) / sizeof(gUartData[0]))) {
  661.         sizeOrErrorCode = CELLULAR_PORT_NOT_INITIALISED;
  662.         if (gUartData[uart].mutex != NULL) {
  663.  
  664.             CELLULAR_PORT_MUTEX_LOCK(gUartData[uart].mutex);
  665.  
  666.             // Move along the buffers copying out
  667.             // everything we can from each one
  668.             sizeOrErrorCode = 0;
  669.             pRxBuffer = gUartData[uart].pRxBufferRead;
  670.             for (size_t x = 0; (sizeBytes > 0) &&
  671.                                (x < sizeof(gUartData[uart].rxBufferList) /
  672.                                     sizeof(gUartData[uart].rxBufferList[0])); x++) {
  673.                 // Read what we can from the current
  674.                 // receive read buffer
  675.                 thisRead = pRxBuffer->toRead;
  676.                 if (thisRead > sizeBytes) {
  677.                     thisRead = sizeBytes;
  678.                 }
  679.                 pCellularPort_memcpy(pBuffer,
  680.                                      pRxBuffer->pRead,
  681.                                      thisRead);
  682.                 // Move buffer pointer and reduce read count
  683.                 // by what we've read
  684.                 pBuffer += thisRead;
  685.                 pRxBuffer->toRead -= thisRead;
  686.                 if (pRxBuffer->toRead <= 0) {
  687.                     // If we've read everything from this
  688.                     // receive read buffer, move
  689.                     // its read pointer back to the start
  690.                     // and move on
  691.                     pRxBuffer->pRead = pRxBuffer->pStart;
  692.                     pRxBuffer = pRxBuffer->pNext;
  693.                 } else {
  694.                     // Otherwise just move the read pointer
  695.                     // on within the current receive read buffer
  696.                     pRxBuffer->pRead += thisRead;
  697.                 }
  698.                 // Update the totals
  699.                 sizeOrErrorCode += thisRead;
  700.                 sizeBytes -= thisRead;
  701.             }
  702.  
  703.             // Set the receive read buffer to where we've got to
  704.             gUartData[uart].pRxBufferRead = pRxBuffer;
  705.  
  706.             // Set the notify flag if we've read everything
  707.             gUartData[uart].userNeedsNotify = false;
  708.             if (pRxBuffer->toRead == 0) {
  709.                 gUartData[uart].userNeedsNotify = true;
  710.             }
  711.  
  712.             CELLULAR_PORT_MUTEX_UNLOCK(gUartData[uart].mutex);
  713.         }
  714.     }
  715.  
  716.     return (int32_t) sizeOrErrorCode;
  717. }
  718.  
  719. // Write to the given UART interface.
  720. int32_t cellularPortUartWrite(int32_t uart,
  721.                               const char *pBuffer,
  722.                               size_t sizeBytes)
  723. {
  724.     CellularPortErrorCode_t sizeOrErrorCode = CELLULAR_PORT_INVALID_PARAMETER;
  725.     const char *pTxBuffer = NULL;
  726.     char *pTmpBuffer = NULL;
  727.     NRF_UARTE_Type *pReg;
  728.  
  729.     if ((pBuffer != NULL) &&
  730.         (uart < sizeof(gUartData) / sizeof(gUartData[0]))) {
  731.         sizeOrErrorCode = CELLULAR_PORT_NOT_INITIALISED;
  732.         if (gUartData[uart].mutex != NULL) {
  733.  
  734.             CELLULAR_PORT_MUTEX_LOCK(gUartData[uart].mutex);
  735.  
  736.             sizeOrErrorCode = CELLULAR_PORT_OUT_OF_MEMORY;
  737.             pReg = gUartData[uart].pReg;
  738.  
  739.             // If the provided buffer is not good for
  740.             // DMA (e.g. if it's in flash) then copy
  741.             // it to somewhere that is
  742.             if (!isGoodForDma(pBuffer)) {
  743.                 pTmpBuffer = pCellularPort_malloc(sizeBytes);
  744.                 if (pTmpBuffer != NULL) {
  745.                     pCellularPort_memcpy(pTmpBuffer, pBuffer, sizeBytes);
  746.                     pTxBuffer = pTmpBuffer;
  747.                 }
  748.             } else {
  749.                 pTxBuffer = pBuffer;
  750.             }
  751.  
  752.             if (pTxBuffer != NULL) {
  753.                 // Set up the flags
  754.                 nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ENDTX);
  755.                 nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_TXSTOPPED);
  756.                 nrf_uarte_tx_buffer_set(pReg, (uint8_t const *) pTxBuffer, sizeBytes);
  757.                 nrf_uarte_task_trigger(pReg, NRF_UARTE_TASK_STARTTX);
  758.  
  759.                 // Wait for the transmission to complete
  760.                 while (!nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_ENDTX)) {}
  761.  
  762.                 // Put UARTE into lowest power state.
  763.                 nrf_uarte_task_trigger(pReg, NRF_UARTE_TASK_STOPTX);
  764.                 while (!nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_TXSTOPPED)) {}
  765.  
  766.                 sizeOrErrorCode = sizeBytes;
  767.             }
  768.  
  769.             // Free memory (it is valid C to free a NULL buffer)
  770.             cellularPort_free(pTmpBuffer);
  771.  
  772.             CELLULAR_PORT_MUTEX_UNLOCK(gUartData[uart].mutex);
  773.         }
  774.     }
  775.  
  776.     return (int32_t) sizeOrErrorCode;
  777. }
  778.  
  779. // Determine if RTS flow control is enabled.
  780. bool cellularPortIsRtsFlowControlEnabled(int32_t uart)
  781. {
  782.     bool rtsFlowControlIsEnabled = false;
  783.     NRF_UARTE_Type *pReg;
  784.  
  785.     if ((uart < sizeof(gUartData) / sizeof(gUartData[0])) &&
  786.         (gUartData[uart].mutex != NULL)) {
  787.  
  788.         CELLULAR_PORT_MUTEX_LOCK(gUartData[uart].mutex);
  789.  
  790.         pReg = gUartData[uart].pReg;
  791.  
  792.         if (nrf_uarte_rts_pin_get(pReg) != NRF_UARTE_PSEL_DISCONNECTED) {
  793.             rtsFlowControlIsEnabled = true;
  794.         }
  795.  
  796.         CELLULAR_PORT_MUTEX_UNLOCK(gUartData[uart].mutex);
  797.     }
  798.  
  799.     return rtsFlowControlIsEnabled;
  800. }
  801.  
  802. // Determine if CTS flow control is enabled.
  803. bool cellularPortIsCtsFlowControlEnabled(int32_t uart)
  804. {
  805.     bool ctsFlowControlIsEnabled = false;
  806.     NRF_UARTE_Type *pReg;
  807.  
  808.     if ((uart < sizeof(gUartData) / sizeof(gUartData[0])) &&
  809.         (gUartData[uart].mutex != NULL)) {
  810.  
  811.         CELLULAR_PORT_MUTEX_LOCK(gUartData[uart].mutex);
  812.  
  813.         pReg = gUartData[uart].pReg;
  814.  
  815.         if (nrf_uarte_cts_pin_get(pReg) != NRF_UARTE_PSEL_DISCONNECTED) {
  816.             ctsFlowControlIsEnabled = true;
  817.         }
  818.  
  819.         CELLULAR_PORT_MUTEX_UNLOCK(gUartData[uart].mutex);
  820.     }
  821.  
  822.     return ctsFlowControlIsEnabled;
  823. }
  824.  
  825. // End of file
Advertisement
Add Comment
Please, Sign In to add comment