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  * Copyright (c) 2016-2017 NXP
00008  * SPDX-License-Identifier: Apache-2.0
00009  *
00010  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00011  * not use this file except in compliance with the License.
00012  * You may obtain a copy of the License at
00013  *
00014  * http://www.apache.org/licenses/LICENSE-2.0
00015  *
00016  * Unless required by applicable law or agreed to in writing, software
00017  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00018  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00019  * See the License for the specific language governing permissions and
00020  * limitations under the License.
00021  */
00022 
00023 #include "string.h"
00024 #include "fsl_device_registers.h"
00025 #include "uart.h"
00026 #include "util.h"
00027 #include "cortex_m.h"
00028 #include "circ_buf.h"
00029 #include "settings.h" // for config_get_overflow_detect
00030 
00031 #define UART_INSTANCE (UART0)
00032 #define UART_IRQ (UART0_RX_TX_IRQn)
00033 
00034 extern uint32_t SystemCoreClock;
00035 
00036 static void clear_buffers(void);
00037 
00038 #define RX_OVRF_MSG         "<DAPLink:Overflow>\n"
00039 #define RX_OVRF_MSG_SIZE    (sizeof(RX_OVRF_MSG) - 1)
00040 #define BUFFER_SIZE         (512)
00041 
00042 
00043 circ_buf_t write_buffer;
00044 uint8_t write_buffer_data[BUFFER_SIZE];
00045 circ_buf_t read_buffer;
00046 uint8_t read_buffer_data[BUFFER_SIZE];
00047 
00048 void clear_buffers(void)
00049 {
00050     util_assert(!(UART_INSTANCE->C2 & UART_C2_TIE_MASK));
00051     circ_buf_init(&write_buffer, write_buffer_data, sizeof(write_buffer_data));
00052     circ_buf_init(&read_buffer, read_buffer_data, sizeof(read_buffer_data));
00053 }
00054 
00055 int32_t uart_initialize(void)
00056 {
00057     NVIC_DisableIRQ(UART_IRQ);
00058     // enable clk PORTC
00059     SIM->SCGC5 |= SIM_SCGC5_PORTB_MASK;
00060     // enable clk uart
00061     SIM->SCGC4 |= SIM_SCGC4_UART0_MASK;
00062 
00063     // disable interrupt
00064     NVIC_DisableIRQ(UART_IRQ);
00065     // transmitter and receiver disabled
00066     UART_INSTANCE->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
00067     // disable interrupt
00068     UART_INSTANCE->C2 &= ~(UART_C2_RIE_MASK | UART_C2_TIE_MASK);
00069 
00070     clear_buffers();
00071 
00072     // Enable receiver and transmitter
00073     UART_INSTANCE->C2 |= UART_C2_RE_MASK | UART_C2_TE_MASK;
00074 
00075     // alternate 3: UART0
00076     PORTB->PCR[16] = PORT_PCR_MUX(3);
00077     PORTB->PCR[17] = PORT_PCR_MUX(3);
00078 
00079     // Enable receive interrupt
00080     UART_INSTANCE->C2 |= UART_C2_RIE_MASK;
00081     NVIC_ClearPendingIRQ(UART_IRQ);
00082     NVIC_EnableIRQ(UART_IRQ);
00083 
00084     return 1;
00085 }
00086 
00087 int32_t uart_uninitialize(void)
00088 {
00089     // transmitter and receiver disabled
00090     UART_INSTANCE->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
00091     // disable interrupt
00092     UART_INSTANCE->C2 &= ~(UART_C2_RIE_MASK | UART_C2_TIE_MASK);
00093     clear_buffers();
00094     return 1;
00095 }
00096 
00097 int32_t uart_reset(void)
00098 {
00099     // disable interrupt
00100     NVIC_DisableIRQ(UART_IRQ);
00101     // disable TIE interrupt
00102     UART_INSTANCE->C2 &= ~(UART_C2_TIE_MASK);
00103     clear_buffers();
00104     // enable interrupt
00105     NVIC_EnableIRQ(UART_IRQ);
00106     return 1;
00107 }
00108 
00109 int32_t uart_set_configuration(UART_Configuration *config)
00110 {
00111     uint8_t data_bits = 8;
00112     uint8_t parity_enable = 0;
00113     uint8_t parity_type = 0;
00114     uint32_t dll;
00115     // disable interrupt
00116     NVIC_DisableIRQ(UART_IRQ);
00117     UART_INSTANCE->C2 &= ~(UART_C2_RIE_MASK | UART_C2_TIE_MASK);
00118     // Disable receiver and transmitter while updating
00119     UART_INSTANCE->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
00120     clear_buffers();
00121 
00122     // set data bits, stop bits, parity
00123     if ((config->DataBits < 8) || (config->DataBits > 9)) {
00124         data_bits = 8;
00125     }
00126 
00127     data_bits -= 8;
00128 
00129     if (config->Parity == 1) {
00130         parity_enable = 1;
00131         parity_type = 1;
00132         data_bits++;
00133     } else if (config->Parity == 2) {
00134         parity_enable = 1;
00135         parity_type = 0;
00136         data_bits++;
00137     }
00138 
00139     // does not support 10 bit data comm
00140     if (data_bits == 2) {
00141         data_bits = 0;
00142         parity_enable = 0;
00143         parity_type = 0;
00144     }
00145 
00146     // data bits, parity and parity mode
00147     UART_INSTANCE->C1 = data_bits << UART_C1_M_SHIFT
00148                 | parity_enable << UART_C1_PE_SHIFT
00149                 | parity_type << UART_C1_PT_SHIFT;
00150     dll =  SystemCoreClock / (16 * config->Baudrate);
00151     // set baudrate
00152     UART_INSTANCE->BDH = (UART_INSTANCE->BDH & ~(UART_BDH_SBR_MASK)) | ((dll >> 8) & UART_BDH_SBR_MASK);
00153     UART_INSTANCE->BDL = (UART_INSTANCE->BDL & ~(UART_BDL_SBR_MASK)) | (dll & UART_BDL_SBR_MASK);
00154     // Enable transmitter and receiver
00155     UART_INSTANCE->C2 |= UART_C2_RE_MASK | UART_C2_TE_MASK;
00156     // Enable UART interrupt
00157     NVIC_ClearPendingIRQ(UART_IRQ);
00158     NVIC_EnableIRQ(UART_IRQ);
00159     UART_INSTANCE->C2 |= UART_C2_RIE_MASK;
00160     return 1;
00161 }
00162 
00163 int32_t uart_get_configuration(UART_Configuration *config)
00164 {
00165     return 1;
00166 }
00167 
00168 int32_t uart_write_free(void)
00169 {
00170     return circ_buf_count_free(&write_buffer);
00171 }
00172 
00173 int32_t uart_write_data(uint8_t *data, uint16_t size)
00174 {
00175     cortex_int_state_t state;
00176     uint32_t cnt;
00177 
00178     cnt = circ_buf_write(&write_buffer, data, size);
00179 
00180     // Atomically enable TX
00181     state = cortex_int_get_and_disable();
00182     if (circ_buf_count_used(&write_buffer)) {
00183         UART_INSTANCE->C2 |= UART_C2_TIE_MASK;
00184     }
00185     cortex_int_restore(state);
00186 
00187     return cnt;
00188 }
00189 
00190 int32_t uart_read_data(uint8_t *data, uint16_t size)
00191 {
00192     return circ_buf_read(&read_buffer, data, size);
00193 }
00194 
00195 void UART0_RX_TX_IRQHandler(void)
00196 {
00197     uint32_t s1;
00198     volatile uint8_t errorData;
00199     // read interrupt status
00200     s1 = UART_INSTANCE->S1;
00201     // mask off interrupts that are not enabled
00202     if (!(UART_INSTANCE->C2 & UART_C2_RIE_MASK)) {
00203         s1 &= ~UART_S1_RDRF_MASK;
00204     }
00205     if (!(UART_INSTANCE->C2 & UART_C2_TIE_MASK)) {
00206         s1 &= ~UART_S1_TDRE_MASK;
00207     }
00208 
00209     // handle character to transmit
00210     if (s1 & UART_S1_TDRE_MASK) {
00211         // Assert that there is data in the buffer
00212         util_assert(circ_buf_count_used(&write_buffer) > 0);
00213 
00214         // Send out data
00215         UART_INSTANCE->D = circ_buf_pop(&write_buffer);
00216         // Turn off the transmitter if that was the last byte
00217         if (circ_buf_count_used(&write_buffer) == 0) {
00218             // disable TIE interrupt
00219             UART_INSTANCE->C2 &= ~(UART_C2_TIE_MASK);
00220         }
00221     }
00222 
00223     // handle received character
00224     if (s1 & UART_S1_RDRF_MASK) {
00225         if ((s1 & UART_S1_NF_MASK) || (s1 & UART_S1_FE_MASK)) {
00226             errorData = UART_INSTANCE->D;
00227         } else {
00228             uint32_t free;
00229             uint8_t data;
00230 
00231             data = UART_INSTANCE->D;
00232             free = circ_buf_count_free(&read_buffer);
00233             if (free > RX_OVRF_MSG_SIZE) {
00234                 circ_buf_push(&read_buffer, data);
00235             } else if ((RX_OVRF_MSG_SIZE == free) && config_get_overflow_detect()) {
00236                 circ_buf_write(&read_buffer, (uint8_t*)RX_OVRF_MSG, RX_OVRF_MSG_SIZE);
00237             } else {
00238                 // Drop character
00239             }
00240         }
00241     }
00242 }