Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 }
Generated on Tue Jul 12 2022 15:37:25 by
1.7.2