Arrow / Mbed OS DAPLink Reset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers uart.c Source File

uart.c

00001 /**
00002  * @file    uart.c
00003  * @brief
00004  *
00005  * DAPLink Interface Firmware
00006  * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
00007  * SPDX-License-Identifier: Apache-2.0
00008  *
00009  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00010  * not use this file except in compliance with the License.
00011  * You may obtain a copy of the License at
00012  *
00013  * http://www.apache.org/licenses/LICENSE-2.0
00014  *
00015  * Unless required by applicable law or agreed to in writing, software
00016  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00017  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00018  * See the License for the specific language governing permissions and
00019  * limitations under the License.
00020  */
00021 
00022 #include "string.h"
00023 
00024 #include "sam3u.h"
00025 #include "uart.h"
00026 #include "circ_buf.h"
00027 #include "cortex_m.h"
00028 #include "util.h"
00029 #include "settings.h" // for config_get_overflow_detect
00030 
00031 #define  BUFFER_SIZE  512
00032 #define _CPU_CLK_HZ   SystemCoreClock
00033 
00034 #define RX_OVRF_MSG         "<DAPLink:Overflow>\n"
00035 #define RX_OVRF_MSG_SIZE    (sizeof(RX_OVRF_MSG) - 1)
00036 
00037 
00038 #define I8   int8_t
00039 #define I16  int16_t
00040 #define I32  int32_t
00041 #define U8   uint8_t
00042 #define U16  uint16_t
00043 #define U32  uint32_t
00044 
00045 #define BIT_CDC_USB2UART_CTS  (9)
00046 #define BIT_CDC_USB2UART_RTS  (10)
00047 
00048 #define UART_PID              (8)
00049 #define UART_RX_PIN           (11)
00050 #define UART_TX_PIN           (12)
00051 #define UART_RXRDY_FLAG       (1uL << 0)              // Rx status flag
00052 #define UART_TXRDY_FLAG       (1uL << 1)              // Tx RDY Status flag
00053 #define UART_TXEMPTY_FLAG     (1uL << 9)              // Tx EMPTY Status flag
00054 #define UART_ENDTX_FLAG       (1uL << 4)              // Tx end flag
00055 #define UART_RX_ERR_FLAGS     (0xE0)                  // Parity, framing, overrun error
00056 #define UART_TX_INT_FLAG      UART_TXEMPTY_FLAG
00057 #define PIO_UART_PIN_MASK     ((1uL << UART_RX_PIN) | (1uL << UART_TX_PIN))
00058 
00059 #define PMC_BASE_ADDR         (0x400E0400)
00060 #define PMC_PCER              *(volatile U32*)(PMC_BASE_ADDR + 0x10)    // Peripheral clock enable register
00061 
00062 #define UART_BASE_ADDR        (0x400E0600)
00063 #define OFF_UART_CR           (0x00)
00064 #define OFF_UART_MR           (0x04)
00065 #define OFF_UART_IER          (0x08)
00066 #define OFF_UART_IDR          (0x0C)
00067 #define OFF_UART_IMR          (0x10)
00068 #define OFF_UART_SR           (0x14)
00069 #define OFF_UART_RHR          (0x18)
00070 #define OFF_UART_THR          (0x1C)
00071 #define OFF_UART_BRGR         (0x20)
00072 #define UART_CR               *(volatile U32*)(UART_BASE_ADDR + OFF_UART_CR)
00073 #define UART_MR               *(volatile U32*)(UART_BASE_ADDR + OFF_UART_MR)
00074 #define UART_IER              *(volatile U32*)(UART_BASE_ADDR + OFF_UART_IER)
00075 #define UART_IDR              *(volatile U32*)(UART_BASE_ADDR + OFF_UART_IDR)
00076 #define UART_IMR              *(volatile U32*)(UART_BASE_ADDR + OFF_UART_IMR)
00077 #define UART_SR               *(volatile U32*)(UART_BASE_ADDR + OFF_UART_SR)
00078 #define UART_RHR              *(volatile U32*)(UART_BASE_ADDR + OFF_UART_RHR)
00079 #define UART_THR              *(volatile U32*)(UART_BASE_ADDR + OFF_UART_THR)
00080 #define UART_BRGR             *(volatile U32*)(UART_BASE_ADDR + OFF_UART_BRGR)
00081 #define OFF_PDC_RPR           (0x100)
00082 #define OFF_PDC_RCR           (0x104)
00083 #define OFF_PDC_TPR           (0x108)
00084 #define OFF_PDC_TCR           (0x10C)
00085 #define OFF_PDC_RNPR          (0x110)
00086 #define OFF_PDC_RNCR          (0x114)
00087 #define OFF_PDC_TNPR          (0x118)
00088 #define OFF_PDC_TNCR          (0x11C)
00089 #define OFF_PDC_PTCR          (0x120)
00090 #define OFF_PDC_PTSR          (0x124)
00091 #define UART_PDC_RPR          *(volatile U32*)(UART_BASE_ADDR + OFF_PDC_RPR)
00092 #define UART_PDC_RCR          *(volatile U32*)(UART_BASE_ADDR + OFF_PDC_RCR)
00093 #define UART_PDC_TPR          *(volatile U32*)(UART_BASE_ADDR + OFF_PDC_TPR)
00094 #define UART_PDC_TCR          *(volatile U32*)(UART_BASE_ADDR + OFF_PDC_TCR)
00095 #define UART_PDC_RNPR         *(volatile U32*)(UART_BASE_ADDR + OFF_PDC_RNPR)
00096 #define UART_PDC_RNCR         *(volatile U32*)(UART_BASE_ADDR + OFF_PDC_RNCR)
00097 #define UART_PDC_TNPR         *(volatile U32*)(UART_BASE_ADDR + OFF_PDC_TNPR)
00098 #define UART_PDC_TNCR         *(volatile U32*)(UART_BASE_ADDR + OFF_PDC_TNCR)
00099 #define UART_PDC_PTCR         *(volatile U32*)(UART_BASE_ADDR + OFF_PDC_PTCR)
00100 #define UART_PDC_PTSR         *(volatile U32*)(UART_BASE_ADDR + OFF_PDC_PTSR)
00101 
00102 #define PIOA_BASE_ADDR        (0x400E0C00)
00103 #define PIOA_PDR             (*(volatile U32*) (PIOA_BASE_ADDR + 0x04)) // PIO Disable Register
00104 #define PIOA_IFER            (*(volatile U32*) (PIOA_BASE_ADDR + 0x20)) // Input Filter Enable Register
00105 #define PIOA_SODR            (*(volatile U32*) (PIOA_BASE_ADDR + 0x30)) // Set output data
00106 #define PIOA_CODR            (*(volatile U32*) (PIOA_BASE_ADDR + 0x34)) // Clear output data register
00107 #define PIOA_PDSR            (*(volatile U32*) (PIOA_BASE_ADDR + 0x3c)) // pin data status register
00108 #define PIOA_IER             (*(volatile U32*) (PIOA_BASE_ADDR + 0x40)) // Interrupt Enable Register
00109 #define PIOA_ISR             (*(volatile U32*) (PIOA_BASE_ADDR + 0x4c)) // Interrupt Status Register
00110 #define PIOA_ABSR            (*(volatile U32*) (PIOA_BASE_ADDR + 0x70)) // Peripheral AB Select Register
00111 #define PIOA_SCIFSR          (*(volatile U32*) (PIOA_BASE_ADDR + 0x80)) // System Clock Glitch Input Filtering Select Register
00112 #define PIOA_AIMER           (*(volatile U32*) (PIOA_BASE_ADDR + 0xB0)) // Additional Interrupt Modes Enable Register
00113 #define PIOA_ESR             (*(volatile U32*) (PIOA_BASE_ADDR + 0xC0)) // Edge Select Register
00114 #define PIOA_FELLSR          (*(volatile U32*) (PIOA_BASE_ADDR + 0xD0)) // Falling Edge/Low Level Select Register
00115 #define PIOA_REHLSR          (*(volatile U32*) (PIOA_BASE_ADDR + 0xD4)) // Rising Edge/High Level Select Register
00116 
00117 circ_buf_t write_buffer;
00118 uint8_t write_buffer_data[BUFFER_SIZE];
00119 circ_buf_t read_buffer;
00120 uint8_t read_buffer_data[BUFFER_SIZE];
00121 
00122 static U32        _Baudrate;
00123 static U8         _FlowControl;
00124 static U8         _UARTChar0;   // Use static here since PDC starts transferring the byte when we already left this function
00125 static U32        _TxInProgress;
00126 static U8         _FlowControlEnabled = 1;
00127 
00128 static U32 _DetermineDivider(U32 Baudrate)
00129 {
00130     U32 Div;
00131     //
00132     // Calculate divider for baudrate and round it correctly.
00133     // This is necessary to get a tolerance as small as possible.
00134     //
00135     Div = Baudrate << 4;
00136     Div = ((_CPU_CLK_HZ << 1) / Div) ;//+ 1;
00137     Div = Div >> 1;
00138     return Div;
00139 }
00140 
00141 static int _SetBaudrate(U32 Baudrate)
00142 {
00143     U32 Div;
00144     Div = _DetermineDivider(Baudrate);
00145 
00146     if (Div >= 1) {
00147         UART_BRGR = Div;
00148         _Baudrate = _CPU_CLK_HZ / Div / 16;
00149         return _Baudrate;
00150     }
00151 
00152     return -1;
00153 }
00154 
00155 static void _Send1(void)
00156 {
00157     // Assert that there is data in the buffer
00158     util_assert(circ_buf_count_used(&write_buffer) > 0);
00159 
00160     //
00161     // Use PDC for transferring the byte to the UART since direct write to UART_THR does not seem to work properly.
00162     //
00163     PIOA->PIO_MDDR = (1 << UART_TX_PIN); //Disable open-drain on TX pin
00164     _UARTChar0 = circ_buf_pop(&write_buffer);
00165 
00166     _TxInProgress = 1;
00167     UART_PDC_TPR  = (U32)&_UARTChar0;
00168     UART_PDC_TCR  = 1;
00169     UART_PDC_PTCR = (1 << 8);               // Enable transmission
00170     UART_IER = UART_TX_INT_FLAG;            // enable Tx interrupt
00171 }
00172 
00173 static void _ResetBuffers(void)
00174 {
00175     //TODO - assert that transmit is off
00176     circ_buf_init(&write_buffer, write_buffer_data, sizeof(write_buffer_data));
00177     circ_buf_init(&read_buffer, read_buffer_data, sizeof(read_buffer_data));
00178     _TxInProgress       = 0;
00179 }
00180 
00181 static int get_tx_ready()
00182 {
00183     if (!_FlowControlEnabled) {
00184         return 1;
00185     }
00186     return ((PIOA->PIO_PDSR >> BIT_CDC_USB2UART_CTS) & 1) == 0;
00187 }
00188 
00189 static void set_rx_ready(int ready)
00190 {
00191     if (ready || !_FlowControlEnabled) {
00192         PIOA->PIO_CODR = 1 << BIT_CDC_USB2UART_RTS;
00193     } else {
00194         PIOA->PIO_SODR = 1 << BIT_CDC_USB2UART_RTS;
00195     }
00196 }
00197 
00198 void UART_IntrEna(void)
00199 {
00200     NVIC_EnableIRQ(UART_IRQn);            // Enable USB interrupt
00201 }
00202 
00203 void UART_IntrDis(void)
00204 {
00205     NVIC_DisableIRQ(UART_IRQn);           // Enable USB interrupt
00206 }
00207 
00208 void uart_set_control_line_state(uint16_t ctrl_bmp)
00209 {
00210 }
00211 
00212 void uart_software_flow_control()
00213 {
00214     int v;
00215 
00216     if (((PIOA->PIO_PDSR >> BIT_CDC_USB2UART_CTS) & 1) == 0) {
00217         _TxInProgress = 0;
00218         v = circ_buf_count_used(&write_buffer); // NumBytes in write buffer
00219 
00220         if (v == 0) {  // No more characters to send ?: Disable further tx interrupts
00221             UART_IER = UART_TX_INT_FLAG;
00222         } else {
00223             _Send1();    //More bytes to send? Trigger sending of next byte
00224         }
00225 
00226     } else {
00227         UART_IDR = UART_TX_INT_FLAG;
00228     }
00229 }
00230 
00231 int32_t uart_initialize(void)
00232 {
00233     //
00234     // Initially, disable UART interrupt
00235     //
00236     UART_IntrDis();
00237     PMC->PMC_WPMR  = 0x504D4300;                     // Disable write protect
00238     PMC->PMC_PCER0 = (1 << UART_PID) | (1 << 10);    // Enable peripheral clock for UART + PIOA
00239     PMC->PMC_WPMR  = 0x504D4301;                     // Enable write protect
00240     PIOA_PDR   = PIO_UART_PIN_MASK;         // Enable peripheral output signals (disable PIO Port A)
00241     PIOA_ABSR &= ~PIO_UART_PIN_MASK;        // Select "A" peripherals on PIO A (UART Rx, Tx)
00242     PIOA->PIO_MDER = PIO_UART_PIN_MASK;     //Enable Multi Drive Control (Open Drain) on the UART Lines so that they don't power nRF51
00243     UART_CR    = (0)
00244                  | (1 <<  2)                  // RSTRX: Reset Receiver: 1 = The receiver logic is reset.
00245                  | (1 <<  3)                  // RSTTX: Reset Transmitter: 1 = The transmitter logic is reset.
00246                  ;
00247     UART_CR    = (0)
00248                  | (0 <<  2)                  // RSTRX: Release Receiver reset
00249                  | (0 <<  3)                  // RSTTX: Release Transmitter reset
00250                  | (1 <<  4)                  // RXEN: Receiver Enable
00251                  | (0 <<  5)                  // RXDIS: Do not disable receiver
00252                  | (1 <<  6)                  // TXEN: Transmitter Enable
00253                  | (0 <<  7)                  // TXDIS: Do not disable transmitter
00254                  | (1 <<  8)                  // RSTSTA: Reset status/error bits
00255                  ;
00256     UART_MR    = (0)
00257                  | (4 <<  9)                  // PAR: Parity Type: 4     => No parity
00258                  | (0 << 14)                  // CHMODE: Channel Mode: 0 => Normal mode
00259                  ;
00260     _SetBaudrate(9600);
00261     _FlowControl = UART_FLOW_CONTROL_NONE;
00262     UART_IDR   = (0xFFFFFFFF);              // Disable all interrupts
00263     //
00264     // Reset all status variables
00265     //
00266     _ResetBuffers();
00267     //
00268     // Enable UART Tx/Rx interrupts
00269     //
00270     UART_IER   = (0)
00271                  | (1 <<  0)                  // Enable Rx Interrupt
00272                  | (0 <<  9)                  // Initially disable TxEmpty Interrupt
00273                  | (0 <<  4)                  // Initially disable ENDTx Interrupt
00274                  ;
00275     //
00276     //Set "RTS" to LOW to indicate that we are ready to receive
00277     //
00278     PIOA_CODR      = (1uL << BIT_CDC_USB2UART_RTS);  // RTS low: Ready to receive data
00279     PIOA->PIO_OER  = (1uL << BIT_CDC_USB2UART_RTS);  // Pins == output
00280     PIOA->PIO_PER  = (1uL << BIT_CDC_USB2UART_RTS);  // Pins == GPIO control
00281     //Set CTS as input
00282     PIOA->PIO_PER  = (1uL << BIT_CDC_USB2UART_CTS);  // Pins == GPIO control
00283     PIOA->PIO_ODR  = (1uL << BIT_CDC_USB2UART_CTS);  // Pins == Input
00284     PIOA->PIO_IER  = (1uL << BIT_CDC_USB2UART_CTS);
00285     //
00286     // Finally, re-enable UART interrupt
00287     //
00288     //NVIC_SetPriority(UART_IRQn, 1);
00289     UART_IntrEna();
00290     return 1;  // O.K. ???
00291 }
00292 
00293 int32_t uart_uninitialize(void)
00294 {
00295     UART_IntrDis();
00296     UART_IDR   = (0xFFFFFFFF);              // Disable all interrupts
00297     _ResetBuffers();
00298     return 1;
00299 }
00300 
00301 int32_t uart_reset(void)
00302 {
00303     uart_initialize();
00304     return 1;
00305 }
00306 
00307 int32_t uart_set_configuration(UART_Configuration *config)
00308 {
00309     //
00310     // UART always works with no parity, 1-stop bit
00311     // Parity bit is configurable but not used in current implementation
00312     //
00313     UART_IntrDis();
00314     UART_IDR   = (0xFFFFFFFF);   // Disable all interrupts
00315     UART_CR    = (0)
00316                  | (1 <<  5)                  // RXDIS: Disable receiver
00317                  | (1 <<  7)                  // TXDIS: Disable transmitter
00318                  | (1 <<  8)                  // RSTSTA: Reset status/error bits
00319                  ;
00320     _FlowControl = config->FlowControl;
00321     _SetBaudrate(config->Baudrate);
00322     UART_CR    = (0)
00323                  | (0 <<  2)                  // RSTRX: Release Receiver reset
00324                  | (0 <<  3)                  // RSTTX: Release Transmitter reset
00325                  | (1 <<  4)                  // RXEN: Receiver Enable
00326                  | (0 <<  5)                  // RXDIS: Do not disable receiver
00327                  | (1 <<  6)                  // TXEN: Transmitter Enable
00328                  | (0 <<  7)                  // TXDIS: Do not disable transmitter
00329                  | (1 <<  8)                  // RSTSTA: Reset status/error bits
00330                  ;
00331     UART_IER   = (0)
00332                  | (1 <<  0)                  // Enable Rx Interrupt
00333                  | (0 <<  9)                  // Initially disable TxEmpty Interrupt
00334                  | (0 <<  4)                  // Initially disable ENDTx Interrupt
00335                  ;
00336     _ResetBuffers();
00337     UART_IntrEna();
00338     return 1;
00339 }
00340 
00341 
00342 int32_t uart_get_configuration(UART_Configuration *config)
00343 {
00344     config->Baudrate    = _Baudrate;
00345     config->DataBits    = UART_DATA_BITS_8;
00346     config->FlowControl = (UART_FlowControl) _FlowControl;//UART_FLOW_CONTROL_NONE;
00347     config->Parity      = UART_PARITY_NONE;
00348     config->StopBits    = UART_STOP_BITS_1;
00349     return 1;
00350 }
00351 
00352 int32_t uart_write_free(void)
00353 {
00354     return circ_buf_count_free(&write_buffer);
00355 }
00356 
00357 
00358 int32_t uart_write_data(uint8_t *data, uint16_t size)
00359 {
00360     cortex_int_state_t state;
00361     uint32_t cnt;
00362 
00363     cnt = circ_buf_write(&write_buffer, data, size);
00364 
00365     //
00366     // Atomically trigger transfer if not already in progress
00367     //
00368     state = cortex_int_get_and_disable();
00369     if (_TxInProgress == 0 && get_tx_ready()) {
00370         _Send1();
00371     }
00372     cortex_int_restore(state);
00373 
00374     return cnt;
00375 }
00376 
00377 int32_t uart_read_data(uint8_t *data, uint16_t size)
00378 {
00379     cortex_int_state_t state;
00380     uint32_t cnt;
00381 
00382     cnt = circ_buf_read(&read_buffer, data, size);
00383 
00384     // Atomically check if RTS had been asserted, if there is space on the buffer then deassert RTS
00385     state = cortex_int_get_and_disable();
00386     if (circ_buf_count_free(&read_buffer) > RX_OVRF_MSG_SIZE) {
00387         set_rx_ready(1);
00388     }
00389     cortex_int_restore(state);
00390 
00391     return cnt;
00392 }
00393 
00394 void uart_enable_flow_control(bool enabled)
00395 {
00396     _FlowControlEnabled = (U8)enabled;
00397 }
00398 
00399 void UART_IRQHandler(void)
00400 {
00401     int Status;
00402     int32_t cnt;
00403     U8 data;
00404     Status = UART_SR;                                 // Examine status register
00405 
00406     if (Status & UART_RX_ERR_FLAGS) {                 // In case of error: Set RSTSTA to reset status bits PARE, FRAME, OVRE and RXBRK
00407         UART_CR = (1 << 8);
00408     }
00409 
00410     //
00411     // Handle Rx event
00412     //
00413     if (Status & UART_RXRDY_FLAG) {                   // Data received?
00414         data = UART_RHR;
00415         cnt = (int32_t)circ_buf_count_free(&read_buffer) - RX_OVRF_MSG_SIZE;
00416         if (cnt > 0) {
00417             circ_buf_push(&read_buffer, data);
00418         } else if (config_get_overflow_detect()) {
00419             if (0 == cnt) {
00420                 circ_buf_write(&read_buffer, (uint8_t*)RX_OVRF_MSG, RX_OVRF_MSG_SIZE);
00421             } else {
00422                 // Drop newest
00423             }
00424         } else {
00425             // Drop oldest
00426             circ_buf_pop(&read_buffer);
00427             circ_buf_push(&read_buffer, data);
00428         }
00429 
00430         //If this was the last available byte on the buffer then assert RTS
00431         if (cnt == 1) {
00432             set_rx_ready(0);
00433         }
00434     }
00435 
00436     //
00437     // Handle Tx event
00438     //
00439     if (Status & UART_IMR & UART_TX_INT_FLAG) {       // Byte has been send by UART
00440         cnt = circ_buf_count_used(&write_buffer); // NumBytes in write buffer
00441         if (cnt == 0) {                               // No more characters to send ?: Disable further tx interrupts
00442             UART_IDR = UART_TX_INT_FLAG;
00443             PIOA->PIO_MDER = (1 << UART_TX_PIN);    //enable open-drain
00444             _TxInProgress = 0;
00445         } else if (get_tx_ready()) {
00446             _Send1();                               //More bytes to send? Trigger sending of next byte
00447         } else {
00448             UART_IDR = UART_TX_INT_FLAG;            // disable Tx interrupt
00449             PIOA->PIO_MDER = (1 << UART_TX_PIN);    //enable open-drain
00450         }
00451     }
00452 }