Commit 1d024609 authored by Preet Kang's avatar Preet Kang
Browse files

closes #26: Fix uart issues

parent d3ac355b
......@@ -3,6 +3,19 @@
This is a sample project for the SJ2 board, written in C that anyone can understand easily.
## Setup and Install
Setup and install should be super simple unless you have windows, which is not suited for ideal software development, but these steps should still get you setup regardless of your OS.
1. Install Python on windows (Mac and Linux should already have that)
* Skip this for Mac or Linux
* Follow [this guide](installs/README.md) for windows install guide
2. Open up a terminal window, and type `pip install scons`
3. Install the Board driver from the `drivers` directory.
That is it, you should now be ready to build software for your board.
## Compile & Flash
1. Use any IDE and open up the `source` or `lpc40xx_freertos` folder
......
# Install Requirements
## Python
Python is usually pre-installed for Mac and Linux, but on windows, run 'python-3.7.4.exe' and then follow these steps:
1. Open the installer and click on 'Customize Installation'
2. Click next (optionally you can de-select 'Documentation' check-box)
3. Ensure 'Add Python to environmental variables' is checked
## SCons
Installation of `scons` requires python to be invokable on your command-line. Python gives you `pip` and you can use it to install `scons`:
1. Open up a terminal window and ensure python is installed: `python --version`
2. `pip install scons`
### Install Scons manually
If you successfully installed using the steps above, then you do not have to follow this section. The `scons-3.1.0.zip` is provided in case you want to install it manually, which can be done by doing:
1. Extract the zip file
2. `cd` into the zip file and then `python scons.py install`
#include "clock.h"
uint32_t clock__get_core_clock_hz(void)
{
static const uint32_t core_clock = 12000000UL;
return core_clock;
}
/**
* FreeRTOS 'configCPU_CLOCK_HZ' references this code to get the CPU frequency.
* Then, the Cortex-M4 port uses that reference to configure the RTOS tick rate.
*
* We use fixed CPU frequency because startup.h configures fixed CPU frequency, so
* unfortunately startup.c implementation needs to match this number but it is rare
* that anyone needs to change this (ever).
*/
uint32_t clock__get_core_clock_hz(void) { return (96UL * 1000 * 1000); }
......@@ -2,16 +2,16 @@
extern void main(void);
void cpu_startup_entry_point(void)
{
startup__initialize_ram();
startup__initialize_fpu();
startup__initialize_system_clock();
main();
void cpu_startup_entry_point(void) {
startup__initialize_ram();
startup__initialize_fpu();
startup__initialize_system_clock_96mhz();
main();
/**
* main() should never return.
* CPU will now halt forever at this point.
*/
while (1 == 1) {}
/**
* main() should never return.
* CPU will now halt forever at this point.
*/
while (1) {
}
}
......@@ -7,68 +7,62 @@ static void ram__init_data_sram_peripheral(void);
static void ram__init_bss_sram_main(void);
static void ram__init_bss_sram_peripheral(void);
void ram__init_data(void)
{
ram__init_data_sram_main();
ram__init_data_sram_peripheral();
void ram__init_data(void) {
ram__init_data_sram_main();
ram__init_data_sram_peripheral();
}
void ram__init_bss(void)
{
ram__init_bss_sram_main();
ram__init_bss_sram_peripheral();
void ram__init_bss(void) {
ram__init_bss_sram_main();
ram__init_bss_sram_peripheral();
}
static void ram__init_data_sram_main(void)
{
extern uint8_t _bdata_lma;
extern uint8_t _bdata_vma;
extern uint8_t _edata;
static void ram__init_data_sram_main(void) {
extern uint8_t _bdata_lma;
extern uint8_t _bdata_vma;
extern uint8_t _edata;
uint8_t *src = &_bdata_lma;
uint8_t *dest = &_bdata_vma;
while (dest < &_edata) {
*dest = *src;
dest++;
src++;
}
uint8_t *src = &_bdata_lma;
uint8_t *dest = &_bdata_vma;
while (dest < &_edata) {
*dest = *src;
dest++;
src++;
}
}
static void ram__init_data_sram_peripheral(void)
{
extern uint8_t _bdata_lma_peripheral;
extern uint8_t _bdata_vma_peripheral;
extern uint8_t _edata_peripheral;
static void ram__init_data_sram_peripheral(void) {
extern uint8_t _bdata_lma_peripheral;
extern uint8_t _bdata_vma_peripheral;
extern uint8_t _edata_peripheral;
uint8_t *src = &_bdata_lma_peripheral;
uint8_t *dest = &_bdata_vma_peripheral;
while (dest < &_edata_peripheral) {
*dest = *src;
dest++;
src++;
}
uint8_t *src = &_bdata_lma_peripheral;
uint8_t *dest = &_bdata_vma_peripheral;
while (dest < &_edata_peripheral) {
*dest = *src;
dest++;
src++;
}
}
static void ram__init_bss_sram_main(void)
{
extern uint8_t _bbss;
extern uint8_t _ebss;
static void ram__init_bss_sram_main(void) {
extern uint8_t _bbss;
extern uint8_t _ebss;
uint8_t *ptr = &_bbss;
while (ptr < &_ebss) {
*ptr = 0U;
ptr++;
}
uint8_t *ptr = &_bbss;
while (ptr < &_ebss) {
*ptr = 0U;
ptr++;
}
}
static void ram__init_bss_sram_peripheral(void)
{
extern uint8_t _bbss_peripheral;
extern uint8_t _ebss_peripheral;
static void ram__init_bss_sram_peripheral(void) {
extern uint8_t _bbss_peripheral;
extern uint8_t _ebss_peripheral;
uint8_t *ptr = &_bbss_peripheral;
while (ptr < &_ebss_peripheral) {
*ptr = 0U;
ptr++;
}
uint8_t *ptr = &_bbss_peripheral;
while (ptr < &_ebss_peripheral) {
*ptr = 0U;
ptr++;
}
}
......@@ -3,22 +3,38 @@
#include "lpc40xx.h"
#include "ram.h"
void startup__initialize_ram(void)
{
ram__init_data();
ram__init_bss();
void startup__initialize_ram(void) {
ram__init_data();
ram__init_bss();
}
/**
* References:
* - http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0439b/BEHBJHIG.html
*/
void startup__initialize_fpu(void)
{
SCB->CPACR |= (0xF << 20); // Set [23:20]
void startup__initialize_fpu(void) {
SCB->CPACR |= (0xF << 20); // Set [23:20]
}
void startup__initialize_system_clock(void)
{
// TODO: Change default core clock
void startup__initialize_system_clock_96mhz(void) {
// Step 3 from UM: Write PLL new setup values to the PLL CFG register
const uint8_t multiplier = 8; // 8 * 12Mhz = 96Mhz
LPC_SC->PLL0CFG = ((multiplier - 1) << 0);
LPC_SC->PLL0CON = 1; // PLL enable
// Necessary feed sequence to ensure the changes are intentional
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
// Step 4 from UM: Setup necessary clock dividers
LPC_SC->PCLKSEL = 1; // APB peripherals receive clock/1 (divided by 1)
const uint32_t pll_lock_bit_mask = (1 << 10);
while (!(LPC_SC->PLL0STAT & pll_lock_bit_mask)) {
;
}
const uint32_t cpu_on_pll_clock = (1 << 8) | (1 << 0);
LPC_SC->CCLKSEL = cpu_on_pll_clock; // CPU uses PLL clock (Table 20)
}
......@@ -8,4 +8,4 @@
void startup__initialize_ram(void);
void startup__initialize_fpu(void);
void startup__initialize_system_clock(void);
void startup__initialize_system_clock_96mhz(void);
......@@ -11,7 +11,7 @@
#define PRIORITY_CRITICAL 4
#define configUSE_PREEMPTION 1
#define configCPU_CLOCK_HZ ((unsigned long)(12*1000*1000))
#define configCPU_CLOCK_HZ (clock__get_core_clock_hz())
#define configTICK_RATE_HZ ((TickType_t) 1000)
#define configMAX_PRIORITIES ((PRIORITY_CRITICAL ) + 1)
#define configMINIMAL_STACK_SIZE ((unsigned short) 128)
......
......@@ -36,7 +36,7 @@ void gpio__set_function(gpio_s gpio, gpio__function_e function) {
volatile uint32_t *pin_config = pin_offset;
// Reference chapter 7: table 83
const uint32_t config_mask = UINT32_C(3);
const uint32_t config_mask = UINT32_C(7);
*pin_config &= ~(config_mask << 0);
*pin_config |= ((uint32_t)function & config_mask);
}
......
......@@ -17,6 +17,7 @@ typedef struct {
lpc_uart *registers;
lpc_peripheral_e peripheral_id;
function__void_f isr_callback;
bool initialized;
QueueHandle_t queue_transmit;
QueueHandle_t queue_receive;
......@@ -61,8 +62,8 @@ static bool uart__is_receive_queue_enabled(uart_e uart) { return (NULL != uarts[
static bool uart__is_transmit_queue_enabled(uart_e uart) { return (NULL != uarts[uart].queue_transmit); }
static void uart__wait_for_transmit_to_complete(lpc_uart *uart_regs) {
const uint32_t char_sent_bitmask = (1 << 6);
while (!(uart_regs->LSR & char_sent_bitmask)) {
const uint32_t transmitter_empty = (1 << 5);
while (!(uart_regs->LSR & transmitter_empty)) {
}
}
......@@ -180,22 +181,34 @@ static void uart__isr_common(uart_s *uart_type) {
void uart__init(uart_e uart, uint32_t peripheral_clock, uint32_t baud_rate) {
if (!uart__is_initialized(uart)) {
lpc_peripheral__turn_on_power_to(uarts[uart].peripheral_id);
const float roundup_offset = 0.5;
const uint16_t divider = (peripheral_clock / (16 * baud_rate) + roundup_offset);
const uint16_t divider = (uint16_t)(peripheral_clock / (16 * baud_rate)) + roundup_offset;
const uint8_t dlab_bit = (1 << 7);
const uint8_t eight_bit_datalen = 3;
lpc_peripheral__turn_on_power_to(uarts[uart].peripheral_id);
// 2-stop bits helps improve baud rate error; you can remove this if bandwidth is critical to you
const uint8_t stop_bits_is_2 = (1 << 2);
lpc_uart *uart_regs = uarts[uart].registers;
uart_regs->LCR = dlab_bit; // Set DLAB bit to access DLM & DLL
uart_regs->DLM = (divider >> 8) & 0xFF;
uart_regs->DLL = (divider >> 0) & 0xFF;
uart_regs->LCR = eight_bit_datalen; // DLAB is reset back to zero also
/* Bootloader uses fractional dividers and can wreck havoc in our baud rate code, so re-initialize it
* Lesson learned: DO NOT RELY ON RESET VALUES
*/
const uint32_t default_reset_fdr_value = (1 << 4);
uart_regs->FDR = default_reset_fdr_value;
uart_regs->LCR = eight_bit_datalen | stop_bits_is_2; // DLAB is reset back to zero also
uarts[uart].initialized = true;
}
}
bool uart__is_initialized(uart_e uart) { return (0 != uarts[uart].registers->LCR); }
bool uart__is_initialized(uart_e uart) { return uarts[uart].initialized; }
bool uart__enable_queues(uart_e uart, QueueHandle_t queue_receive, QueueHandle_t queue_transmit) {
bool status = false;
......
#include <stdbool.h>
#include "lpc40xx.h"
#include "FreeRTOS.h"
#include "task.h"
#include "delay.h"
#include "gpio.h"
#include "sys_time.h"
#include "clock.h"
#include "FreeRTOS.h"
#include "task.h"
#include "uart.h"
#include "uart_printf.h"
static void blink_task(void *params);
static void uart_task(void *params);
static void blink_on_startup(gpio_s gpio);
static void uart0_init(void);
static gpio_s led0, led1;
int main(void) {
sys_time__init(configCPU_CLOCK_HZ);
sys_time__init(clock__get_core_clock_hz());
led0 = gpio__instantiate(gpio__port_2, 3);
led1 = gpio__instantiate(gpio__port_1, 26);
gpio__set_as_output(led0);
gpio__set_as_output(led1);
uart0_init();
blink_on_startup(led1);
xTaskCreate((TaskFunction_t)blink_task, "led0", 512U, (void *)&led0, PRIORITY_HIGH, NULL);
xTaskCreate((TaskFunction_t)blink_task, "led1", 512U, (void *)&led1, PRIORITY_HIGH, NULL);
xTaskCreate(blink_task, "led0", 512U, (void *)&led0, PRIORITY_LOW, NULL);
xTaskCreate(blink_task, "led1", 512U, (void *)&led1, PRIORITY_LOW, NULL);
xTaskCreate(uart_task, "uart", 512U, NULL, PRIORITY_LOW, NULL);
vTaskStartScheduler();
......@@ -42,15 +53,42 @@ int main(void) {
static void blink_task(void *params) {
const gpio_s gpio = *((gpio_s *)params);
while (1 == 1) {
while (true) {
gpio__toggle(gpio);
vTaskDelay(250);
vTaskDelay(500);
}
}
static void uart_task(void *params) {
while (true) {
vTaskDelay(500);
// Wait until the data is fully printed before moving on
uart_printf__polled(UART__0, "Hello world\n");
// This deposits data to an outgoing queue and doesn't block the CPU
uart_printf(UART__0, " ... and a more efficient printf...\n");
}
}
static void blink_on_startup(gpio_s gpio) {
for (int i = 0; i < 10; i++) {
delay__ms(250);
delay__ms(100);
gpio__toggle(gpio);
}
}
static void uart0_init(void) {
const gpio_s u0_txd = gpio__instantiate(gpio__port_0, 2); // P0.2
const gpio_s u0_rxd = gpio__instantiate(gpio__port_0, 3); // P0.3
gpio__set_function(u0_txd, gpio__function_1);
gpio__set_function(u0_rxd, gpio__function_1);
uart__init(UART__0, clock__get_core_clock_hz(), 115200);
// Make UART more efficient by backing it with RTOS queues (optional but highly recommended)
QueueHandle_t tx_queue = xQueueCreate(128, sizeof(char));
QueueHandle_t rx_queue = xQueueCreate(32, sizeof(char));
uart__enable_queues(UART__0, tx_queue, rx_queue);
}
start cd .
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment