Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
Diff: source/hic_hal/freescale/kl26z/uart.c
- Revision:
- 0:01f31e923fe2
diff -r 000000000000 -r 01f31e923fe2 source/hic_hal/freescale/kl26z/uart.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/hic_hal/freescale/kl26z/uart.c Tue Apr 07 12:55:42 2020 +0200 @@ -0,0 +1,266 @@ +/** + * @file uart.c + * @brief + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "string.h" + +#include "uart.h" +#include "util.h" +#include "cortex_m.h" +#include "IO_Config.h" +#include "circ_buf.h" +#include "settings.h" // for config_get_overflow_detect + +#define RX_OVRF_MSG "<DAPLink:Overflow>\n" +#define RX_OVRF_MSG_SIZE (sizeof(RX_OVRF_MSG) - 1) +#define BUFFER_SIZE (512) + +circ_buf_t write_buffer; +uint8_t write_buffer_data[BUFFER_SIZE]; +circ_buf_t read_buffer; +uint8_t read_buffer_data[BUFFER_SIZE]; + +void clear_buffers(void) +{ + util_assert(!(UART->C2 & UART_C2_TIE_MASK)); + circ_buf_init(&write_buffer, write_buffer_data, sizeof(write_buffer_data)); + circ_buf_init(&read_buffer, read_buffer_data, sizeof(read_buffer_data)); +} + +int32_t uart_initialize(void) +{ + NVIC_DisableIRQ(UART_RX_TX_IRQn); + + // enable clk port + if (UART_PORT == PORTA) { + SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; + } + + if (UART_PORT == PORTC) { + SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK; + } + + if (UART_PORT == PORTD) { + SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; + } + + if (UART_PORT == PORTE) { + SIM->SCGC5 |= SIM_SCGC5_PORTE_MASK; + } + + // enable clk uart + if (1 == UART_NUM) { + SIM->SCGC4 |= SIM_SCGC4_UART1_MASK; + } + + if (2 == UART_NUM) { + SIM->SCGC4 |= SIM_SCGC4_UART2_MASK; + } + + // transmitter and receiver disabled + UART->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK); + // disable interrupt + UART->C2 &= ~(UART_C2_RIE_MASK | UART_C2_TIE_MASK); + + clear_buffers(); + + // alternate setting + UART_PORT->PCR[PIN_UART_RX_BIT] = PORT_PCR_MUX(PIN_UART_RX_MUX_ALT) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK; + UART_PORT->PCR[PIN_UART_TX_BIT] = PORT_PCR_MUX(PIN_UART_TX_MUX_ALT); + // transmitter and receiver enabled + UART->C2 |= UART_C2_RE_MASK | UART_C2_TE_MASK; + // Enable receive interrupt + UART->C2 |= UART_C2_RIE_MASK; + NVIC_ClearPendingIRQ(UART_RX_TX_IRQn); + NVIC_EnableIRQ(UART_RX_TX_IRQn); + return 1; +} + +int32_t uart_uninitialize(void) +{ + // transmitter and receiver disabled + UART->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK); + // disable interrupt + UART->C2 &= ~(UART_C2_RIE_MASK | UART_C2_TIE_MASK); + clear_buffers(); + return 1; +} + +int32_t uart_reset(void) +{ + // disable interrupt + NVIC_DisableIRQ(UART_RX_TX_IRQn); + // disable TIE interrupt + UART->C2 &= ~(UART_C2_TIE_MASK); + clear_buffers(); + // enable interrupt + NVIC_EnableIRQ(UART_RX_TX_IRQn); + return 1; +} + +int32_t uart_set_configuration(UART_Configuration *config) +{ + uint8_t data_bits = 8; + uint8_t parity_enable = 0; + uint8_t parity_type = 0; + uint32_t dll; + // disable interrupt + NVIC_DisableIRQ(UART_RX_TX_IRQn); + UART->C2 &= ~(UART_C2_RIE_MASK | UART_C2_TIE_MASK); + // Disable receiver and transmitter while updating + UART->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK); + clear_buffers(); + + // set data bits, stop bits, parity + if ((config->DataBits < 8) || (config->DataBits > 9)) { + data_bits = 8; + } + + data_bits -= 8; + + if (config->Parity == 1) { + parity_enable = 1; + parity_type = 1; + data_bits++; + } else if (config->Parity == 2) { + parity_enable = 1; + parity_type = 0; + data_bits++; + } + + // does not support 10 bit data comm + if (data_bits == 2) { + data_bits = 0; + parity_enable = 0; + parity_type = 0; + } + + // data bits, parity and parity mode + UART->C1 = data_bits << UART_C1_M_SHIFT | + parity_enable << UART_C1_PE_SHIFT | + parity_type << UART_C1_PT_SHIFT; + dll = SystemCoreClock / (16 * config->Baudrate); + + if (1 == UART_NUM || 2 == UART_NUM) { + dll /= 2; //TODO <<= 1 + } + + // set baudrate + UART->BDH = (UART->BDH & ~(UART_BDH_SBR_MASK)) | ((dll >> 8) & UART_BDH_SBR_MASK); + UART->BDL = (UART->BDL & ~(UART_BDL_SBR_MASK)) | (dll & UART_BDL_SBR_MASK); + // Enable transmitter and receiver + UART->C2 |= UART_C2_RE_MASK | UART_C2_TE_MASK; + // Enable UART interrupt + NVIC_ClearPendingIRQ(UART_RX_TX_IRQn); + NVIC_EnableIRQ(UART_RX_TX_IRQn); + UART->C2 |= UART_C2_RIE_MASK; + return 1; +} + +int32_t uart_get_configuration(UART_Configuration *config) +{ + return 1; +} + +int32_t uart_write_free(void) +{ + return circ_buf_count_free(&write_buffer); +} + +int32_t uart_write_data(uint8_t *data, uint16_t size) +{ + cortex_int_state_t state; + uint32_t cnt; + + cnt = circ_buf_write(&write_buffer, data, size); + + // Atomically enable TX + state = cortex_int_get_and_disable(); + if (circ_buf_count_used(&write_buffer)) { + UART->C2 |= UART_C2_TIE_MASK; + } + cortex_int_restore(state); + + return cnt; +} + +int32_t uart_read_data(uint8_t *data, uint16_t size) +{ + return circ_buf_read(&read_buffer, data, size); +} + +void uart_enable_flow_control(bool enabled) +{ + // Flow control not implemented for this platform +} + +void UART_RX_TX_IRQHandler(void) +{ + uint32_t s1; + volatile uint8_t errorData; + // read interrupt status + s1 = UART->S1; + // mask off interrupts that are not enabled + if (!(UART->C2 & UART_C2_RIE_MASK)) { + s1 &= ~UART_S1_RDRF_MASK; + } + if (!(UART->C2 & UART_C2_TIE_MASK)) { + s1 &= ~UART_S1_TDRE_MASK; + } + + // handle character to transmit + if (s1 & UART_S1_TDRE_MASK) { + // Assert that there is data in the buffer + util_assert(circ_buf_count_used(&write_buffer) > 0); + // Send out data + UART1->D = circ_buf_pop(&write_buffer); + // Turn off the transmitter if that was the last byte + if (circ_buf_count_used(&write_buffer) == 0) { + // disable TIE interrupt + UART->C2 &= ~(UART_C2_TIE_MASK); + } + } + + // handle received character + if (s1 & UART_S1_RDRF_MASK) { + if ((s1 & UART_S1_NF_MASK) || (s1 & UART_S1_FE_MASK)) { + errorData = UART->D; + } else { + uint32_t free; + uint8_t data; + + data = UART1->D; + free = circ_buf_count_free(&read_buffer); + if (free > RX_OVRF_MSG_SIZE) { + circ_buf_push(&read_buffer, data); + } else if (config_get_overflow_detect()) { + if (RX_OVRF_MSG_SIZE == free) { + circ_buf_write(&read_buffer, (uint8_t*)RX_OVRF_MSG, RX_OVRF_MSG_SIZE); + } else { + // Drop newest + } + } else { + // Drop oldest + circ_buf_pop(&read_buffer); + circ_buf_push(&read_buffer, data); + } + } + } +}