From 8f45739d02f02c226452f7f62c4dc195e6e13b38 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sun, 31 May 2015 15:48:15 +0200 Subject: o Party functional LCD code. --- LiquidCrystal.c | 197 +++++++++++++++++++++++++++++++++++++------------------- LiquidCrystal.h | 16 ++++- Makefile | 2 +- main.c | 38 ++++++++--- nrf51.md | 101 +++++++++++++++++++++++++---- phone_remote.c | 2 +- 6 files changed, 260 insertions(+), 96 deletions(-) diff --git a/LiquidCrystal.c b/LiquidCrystal.c index becc07e..eed30c8 100644 --- a/LiquidCrystal.c +++ b/LiquidCrystal.c @@ -1,13 +1,14 @@ #include "LiquidCrystal.h" +#include "nrf_delay.h" +#include "nrf_error.h" #include "nrf_gpio.h" -#include "app_timer.h" /* * Arduino | LCD | nrf51 * D4 | DB4 | P0.16 * D5 | DB5 | P0.17 * D6 | DB6 | P0.18 - * D7 | DB7 | P0.10 + * D7 | DB7 | P0.19 * D8 | RS | P0.20, register select. 0=instruction (write), 0=busy (read), 1=data * D9 | EN | P0.23, clock, data is clocked in/out on falling edge * D10 | DB4 | P0.24 @@ -31,103 +32,109 @@ static struct { uint8_t pin_db7; uint8_t pin_rs; uint8_t pin_en; - - app_gpiote_user_id_t gpio_user_id; } data = { .pin_db4 = 16, .pin_db5 = 17, .pin_db6 = 18, .pin_db7 = 19, .pin_rs = 20, .pin_en = 23, }; -static uint32_t ticks_per_ms; - -static void event_handler() { -} - -static void wait_ms(uint32_t ms) { - uint32_t ticks; - - app_timer_cnt_get(&ticks); - - const uint32_t end_ticks = ticks + ms * ticks_per_ms; - - do { - app_timer_cnt_get(&ticks); - } while (ticks < end_ticks); -} - static void write_4(uint8_t value) { nrf_gpio_pin_write(data.pin_db4, value & 0x01); nrf_gpio_pin_write(data.pin_db5, value & 0x02); nrf_gpio_pin_write(data.pin_db6, value & 0x04); nrf_gpio_pin_write(data.pin_db7, value & 0x08); + nrf_delay_us(10); nrf_gpio_pin_set(data.pin_en); + nrf_delay_us(10); // 450ns is supposed to be sufficient nrf_gpio_pin_clear(data.pin_en); } -static void write_value(uint8_t value, bool is_data) { +static void write_value(uint8_t value, bool is_data, uint32_t delay) { nrf_gpio_pin_write(data.pin_rs, is_data); write_4(value >> 4); write_4(value); -} - -static void begin() { - nrf_gpio_pin_clear(data.pin_rs); - nrf_gpio_pin_clear(data.pin_en); - // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! - // according to datasheet, we need at least 40ms after power rises above 2.7V - // before sending commands. Arduino can turn on way before 4.5V so we'll wait 50 - wait_ms(50); - - write_4(0x03); - wait_ms(5); // 4.5ms - - write_4(0x03); - wait_ms(5); // 4.5ms - - write_4(0x03); - wait_ms(5); // 4.5ms - - write_4(0x02); - - write_value(LIQUID_CRYSTAL_CMD_DISPLAY, false); - -// _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; - liquid_crystal_display(true, true, true); + nrf_delay_us(delay); } void liquid_crystal_write_char(char chr) { - write_value(chr, true); + write_value(chr, true, 50); } void liquid_crystal_write_string(char *chr) { - while (*chr != '\0') { + for (; *chr != '\0'; chr++) { liquid_crystal_write_char(*chr); } } -uint32_t liquid_crystal_display(bool display_on, bool cursor_on, bool blink) { - uint8_t value = LIQUID_CRYSTAL_CMD_DISPLAY; - - value |= display_on ? 0x04 : 0x00; - value |= cursor_on ? 0x02 : 0x00; - value |= blink ? 0x01 : 0x00; - - write_value(value, false); - - return NRF_SUCCESS; +void liquid_crystal_clear() { + // The documentation doesn't specify a value, but everything else is 37us + write_value(LIQUID_CRYSTAL_CMD_CLEAR, false, 50); } -uint32_t liquid_crystal_init(uint32_t _ticks_per_ms) { - ticks_per_ms = _ticks_per_ms; +void liquid_crystal_return_home() { + write_value(LIQUID_CRYSTAL_CMD_RETURN_HOME, false, 2000); +} - uint32_t err_code = app_gpiote_user_register(&data.gpio_user_id, 0x0000, - 0x0000, event_handler); +static struct { + union { + uint8_t value; + struct { + bool shift :1; + bool increment :1; + int :6; + } fields __attribute__((packed)); + }; +}__attribute__((packed)) entry_mode_state; + +void liquid_crystal_entry_mode_set(bool increment, bool shift) { + /* + uint8_t value = LIQUID_CRYSTAL_CMD_ENTRY_MODE_SET; + + value |= increment ? 0x02 : 0x00; + value |= shift ? 0x01 : 0x00; + + write_value(value, false); + */ + + entry_mode_state.fields.increment = increment; + entry_mode_state.fields.shift = shift; + write_value(entry_mode_state.value, false, 50); +} - if (err_code != NRF_SUCCESS) { - return err_code; - } +static struct { + union { + uint8_t value; + struct { + bool blink :1; + bool cursor_on :1; + bool display_on :1; + int :5; + } fields __attribute__((packed)); + }; +}__attribute__((packed)) display_state; + +void liquid_crystal_display(bool display_on, bool cursor_on, bool blink) { + display_state.fields.display_on = display_on; + display_state.fields.cursor_on = cursor_on; + display_state.fields.blink = blink; + + write_value(display_state.value, false, 50); +} +static struct { + union { + uint8_t value; + struct { + int :2; + bool many_dots :1; + bool two_line :1; + bool data_length :1; + int :3; + } fields __attribute__((packed)); + }; +}__attribute__((packed)) function_set_state; + +void liquid_crystal_init(bool data_length, bool two_line, bool many_dots) { nrf_gpio_cfg_output(data.pin_db4); nrf_gpio_cfg_output(data.pin_db5); nrf_gpio_cfg_output(data.pin_db6); @@ -135,7 +142,61 @@ uint32_t liquid_crystal_init(uint32_t _ticks_per_ms) { nrf_gpio_cfg_output(data.pin_rs); nrf_gpio_cfg_output(data.pin_en); - begin(data); + display_state.value = LIQUID_CRYSTAL_CMD_DISPLAY; + entry_mode_state.value = LIQUID_CRYSTAL_CMD_ENTRY_MODE_SET; + function_set_state.value = LIQUID_CRYSTAL_CMD_FUNCTION_SET; + + function_set_state.fields.data_length = data_length; + function_set_state.fields.two_line = two_line; + function_set_state.fields.many_dots = many_dots; + + for (int i = 0; i < 3; i++) { + nrf_gpio_pin_set(data.pin_en); + nrf_delay_ms(100); + nrf_gpio_pin_clear(data.pin_en); + nrf_delay_ms(100); + } + + // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! + // according to datasheet, we need at least 40ms after power rises above 2.7V + // before sending commands. Arduino can turn on way before 4.5V so we'll wait 50 + nrf_delay_ms(50); + + nrf_gpio_pin_clear(data.pin_rs); + nrf_gpio_pin_clear(data.pin_en); + + write_4(0x03); + nrf_delay_us(4500); + + write_4(0x03); + nrf_delay_us(4500); + + write_4(0x03); + nrf_delay_us(150); + + write_4(0x02); + + write_value(function_set_state.value, false, 50); +} + +void liquid_crystal_reset() { + liquid_crystal_clear(); + liquid_crystal_return_home(); + liquid_crystal_entry_mode_set(true, false); +} + +void liquid_crystal_set_cursor(int column, int row) { + uint8_t value = LIQUID_CRYSTAL_CMD_SET_DDRAM_ADDDRESS; + + if (row == 1) { + value += 0x40; + } else if (row == 2) { + value += 14; + } else if (row == 3) { + value += 54; + } + + value += column; - return NRF_SUCCESS; + write_value(value, false, 50); } diff --git a/LiquidCrystal.h b/LiquidCrystal.h index 341d729..dd28fc9 100644 --- a/LiquidCrystal.h +++ b/LiquidCrystal.h @@ -6,11 +6,21 @@ #define LIQUIDCRYSTAL_H_ #include -#include "app_gpiote.h" +#include -uint32_t liquid_crystal_init(); +void liquid_crystal_init(bool data_length, bool two_line, bool many_dots); -uint32_t liquid_crystal_display(bool display_on, bool cursor_on, bool blink); +void liquid_crystal_reset(); + +void liquid_crystal_clear(); + +void liquid_crystal_return_home(); + +void liquid_crystal_entry_mode_set(bool increment, bool shift); + +void liquid_crystal_display(bool display_on, bool cursor_on, bool blink); + +void liquid_crystal_set_cursor(int column, int row); void liquid_crystal_write_char(char chr); diff --git a/Makefile b/Makefile index 47155d4..3e58e3a 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ FLASHER ?= jlink -BOARD := BOARD_PCA10028 +BOARD ?= BOARD_PCA10028 #TARGET_CHIP := NRF51822_QFAA_CA #TARGET_CHIP := NRF51422_QFAC_AB diff --git a/main.c b/main.c index 34b8ae4..d79c12b 100644 --- a/main.c +++ b/main.c @@ -22,7 +22,7 @@ #include #include "nordic_common.h" #include "nrf.h" -#include "app_error.h" +#include "nrf_delay.h" #include "nrf51_bitfields.h" #include "ble.h" #include "ble_hci.h" @@ -43,6 +43,7 @@ #include "app_timer.h" #include "device_manager.h" #include "pstorage.h" +#include "app_error.h" #include "app_trace.h" #include "app_timer.h" #include "app_gpiote.h" @@ -293,7 +294,7 @@ static void on_ble_evt(ble_evt_t * p_ble_evt) if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT) { - printf("re-starting advertisement"); + printf("re-starting advertisement\n"); advertising_start(); /* err_code = bsp_indication_set(BSP_INDICATE_IDLE); @@ -399,7 +400,7 @@ int main(void) { app_trace_init(); - dbg("Soil Moisture device starting...\r\n"); + dbg("Phone remote starting...\r\n"); ble_stack_init(); timers_init(); @@ -409,16 +410,33 @@ int main(void) uint32_t err_code = bsp_init(BSP_INIT_LED | BSP_INIT_BUTTONS, APP_TIMER_TICKS(100, APP_TIMER_PRESCALER), NULL); APP_ERROR_CHECK(err_code); -// device_manager_init(); -// gap_params_init(); -// advertising_init(); -// services_init(); -// conn_params_init(); + device_manager_init(); + gap_params_init(); + advertising_init(); + services_init(); + conn_params_init(); timers_start(); - liquid_crystal_init(APP_TIMER_TICKS(1, APP_TIMER_PRESCALER)); - liquid_crystal_write_string("hello world!"); + liquid_crystal_init(false, true, false); + liquid_crystal_reset(); + liquid_crystal_display(true, false, false); + liquid_crystal_write_string("01234567890123456"); +/* + char chars[] = "abcdefghijklmopqrstuvwxyz"; + + for(int i = 0; i < 10; i++) { + nrf_delay_ms(200); + liquid_crystal_write_char(chars[i]); + } + + nrf_delay_ms(1000); +*/ + liquid_crystal_clear(); +// liquid_crystal_return_home(); + + liquid_crystal_set_cursor(1, 1); + liquid_crystal_write_string("hello!"); advertising_start(); diff --git a/nrf51.md b/nrf51.md index 765af1e..0737ca0 100644 --- a/nrf51.md +++ b/nrf51.md @@ -1,5 +1,17 @@ # NRF51 Firmware Development Notes +# Documentation + +nRF51-specific documentation: + +* [nRF51822 Product Specification](http://www.nordicsemi.com/eng/nordic/Products/nRF51822/nRF51822-PS/20339) +* [nRF51822 Reference Manual](http://www.nordicsemi.com/eng/nordic/Products/nRF51822/nRF51-RM/20337) + +Generic ARM documentation: + +* [Cortex™-M0 Devices Generic User Guide](http://infocenter.arm.com/help/topic/com.arm.doc.dui0497a/DUI0497A_cortex_m0_r0p0_generic_ug.pdf) +* [Cortex™-M0 Technical Reference Manual](http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/DDI0432C_cortex_m0_r0p0_trm.pdf) + # Chip Details ## Address Map @@ -21,26 +33,89 @@ ### Flash and RAM Areas -* nRF51822-xxAA flash: 0x0000 0000 => 0x0002 0000, RAM: 0x2000 0000 => 0x2000 4000 -* nRF51822-xxAB flash: 0x0000 0000 => 0x0001 0000, RAM: 0x2000 0000 => 0x2000 4000 -* nRF51822-xxAC flash: 0x0000 0000 => 0x0002 0000, RAM: 0x2000 0000 => 0x2000 8000 +| Device | Flash ||| RAM ||| +Device | Size | Start | End | Size | Start | End | + ------- | ------ | ----------- | ----------- | ------ | ----------- | ----------- | +`xxAA` | 256kB | 0x0000 0000 | 0x0002 0000 | 16kB | 0x2000 0000 | 0x2000 4000 | +`xxAB` | 128kB | 0x0000 0000 | 0x0001 0000 | 16kB | 0x2000 0000 | 0x2000 4000 | +`xxAC` | 256kB | 0x0000 0000 | 0x0002 0000 | 32kB | 0x2000 0000 | 0x2000 8000 | +[Available resources for chip variants] # Debugging screen /dev/ttyACM0 115200,-ixon,-ixoff -## Documentation +## GDB -### Nordic + (gdb) print -* [inRF51822 Product Specification](http://www.nordicsemi.com/eng/nordic/Products/nRF51822/nRF51822-PS/20339) -* [inRF51822 Reference Manual](http://www.nordicsemi.com/eng/nordic/Products/nRF51822/nRF51-RM/20337) + (gdb) info registers -### Generic ARM +## Remote Debugging -* [Cortex™-M0 Devices Generic User Guide](http://infocenter.arm.com/help/topic/com.arm.doc.dui0497a/DUI0497A_cortex_m0_r0p0_generic_ug.pdf) -* [Cortex™-M0 Technical Reference Manual](http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/DDI0432C_cortex_m0_r0p0_trm.pdf) +* `target remote localhost:2331` +* `disconnect` or `detach` +* the generic `monitor` commands sends jlink-specific commands. `monitor reset` + +When using GDB, make sure you use the version for arm: + + arm-none-eabi-gdb + +I often start GDB like this: + + arm-none-eabi-gdb -ex "file build/*.out" -ex "target remote localhost:2331" -ex "monitor reset" + +This select the correct image so you can say `break main`, connects to the JLink remote GDB server and performs a reset of the board. + +# The JLink tools + +## JLinkGDBServer + +This program is normally executed as + + JLinkGDBServer -if SWD + +It should find the target and wait for an TCP connection on port 2331. + +Sometimes it will refuse to listen to the socket, just waiting (around 10 seconds) for a while seems to fix the problem. + +Example output: + + $ JLinkGDBServer -if SWD + SEGGER J-Link GDB Server V4.98e Command Line Version + + JLinkARM.dll V4.98e (DLL compiled May 5 2015 11:49:35) + + -----GDB Server start settings----- + GDBInit file: none + GDB Server Listening port: 2331 + SWO raw output listening port: 2332 + Terminal I/O port: 2333 + Accept remote connection: yes + Generate logfile: off + Verify download: off + Init regs on start: off + Silent mode: off + Single run mode: off + Target connection timeout: 0 ms + ------J-Link related settings------ + J-Link Host interface: USB + J-Link script: none + J-Link settings file: none + ------Target related settings------ + Target device: unspecified + Target interface: SWD + Target interface speed: 1000kHz + Target endian: little -* nRF51822-xxAA flash: 256 kB, ram: 16kB -* nRF51822-xxAB flash: 128 kB, ram: 16kB -* nRF51822-xxAC flash: 256 kB, ram: 32kB + Connecting to J-Link... + J-Link is connected. + Firmware: J-Link OB-SAM3U128-V2-NordicSemi compiled May 4 2015 13:48:48 + Hardware: V1.00 + S/N: 681084376 + Checking target voltage... + Target voltage: 3.30 V + Listening on TCP/IP port 2331 + Connecting to target...WARNING: T-bit of XPSR is 0 but should be 1. Changed to 1. + Connected to target + Waiting for GDB connection... diff --git a/phone_remote.c b/phone_remote.c index c37123a..273e3d2 100644 --- a/phone_remote.c +++ b/phone_remote.c @@ -17,7 +17,7 @@ static uint8_t trygvis_io_uuid_type; static uint16_t pr_service_handle; static ble_gatts_char_handles_t pr_char_handle; -static uint16_t conn_handle = BLE_CONN_HANDLE_INVALID; +//static uint16_t conn_handle = BLE_CONN_HANDLE_INVALID; // The value of the soil moisture control characteristic. static uint8_t control_value[100] = {1, 2, 3}; -- cgit v1.2.3