I am working with a dk along side a custom PCB that is used to read and amplify the signal from a load cell. I cannot change anything on the custom PCB and I need to be able to run a differential ADC using pins 14 and 15, I also need to output on pin 17 to trigger the sensor reading on the custom PCB. I have gotten that all working on an application that only in reading mode. I have an issue when I added that reading file to the aws_iot sample project where both pin 14 and 15 are set to around 1.79V. I am pretty sure this is because UART1 uses pin 14 for RTS and 15 for CTS. My question is how can I turn off or move those functions to different pins. I haven't been able to find what is turning RTS or CTS on. I have found that in the device tree I can change the pins used for RTS and CTS but I feel like this isn't the best solution to the problem.
//In nrf9160dk_nrf9160_common-pinctrl.dtsi uart1_default: uart1_default { group1 { psels = <NRF_PSEL(UART_TX, 0, 1)>, <NRF_PSEL(UART_RTS, 0, 14)>; //Change to 16 }; group2 { psels = <NRF_PSEL(UART_RX, 0, 0)>, <NRF_PSEL(UART_CTS, 0, 15)>; //Change to 18 bias-pull-up; }; }; uart1_sleep: uart1_sleep { group1 { psels = <NRF_PSEL(UART_TX, 0, 1)>, <NRF_PSEL(UART_RX, 0, 0)>, <NRF_PSEL(UART_RTS, 0, 14)>,//Change to 16 <NRF_PSEL(UART_CTS, 0, 15)>;//Change to 18 low-power-enable; }; };It also leaves pin 14 and 15 at around 400mV which I need to be 0. How can I isolate those pins so that they are only used for reading? I would also like to confirm that I am properly using the ADC in differential mode and ask how to properly find pin 17 to output on. I have just changed led0 to use pin 17.
// In nrf9160dk_nrf9160_common.dts leds { compatible = "gpio-leds"; led0: led_0 { gpios = <&gpio0 17 0>; label = "Green LED 1"; }; led1: led_1 { gpios = <&gpio0 3 0>; label = "Green LED 2"; }; led2: led_2 { gpios = <&gpio0 4 0>; label = "Green LED 3"; }; led3: led_3 { gpios = <&gpio0 5 0>; label = "Green LED 4"; }; };
/* * Copyright (c) 2020 Nordic Semiconductor ASA * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ #include <zephyr/kernel.h> #include <stdio.h> #include <stdlib.h> #if defined(CONFIG_NRF_MODEM_LIB) #include <modem/lte_lc.h> #include <modem/nrf_modem_lib.h> #include <modem/modem_info.h> #include <nrf_modem.h> #endif #include <net/aws_iot.h> #include <zephyr/sys/reboot.h> #include <date_time.h> #include <zephyr/dfu/mcuboot.h> #include <cJSON.h> #include <cJSON_os.h> #include <zephyr/logging/log.h> #if defined(CONFIG_AWS_IOT_SAMPLE_DEVICE_ID_USE_HW_ID) #include <hw_id.h> #endif LOG_MODULE_REGISTER(aws_iot_sample, CONFIG_AWS_IOT_SAMPLE_LOG_LEVEL); BUILD_ASSERT(!IS_ENABLED(CONFIG_LTE_AUTO_INIT_AND_CONNECT), "This sample does not support LTE auto-init and connect"); #define APP_TOPICS_COUNT CONFIG_AWS_IOT_APP_SUBSCRIPTION_LIST_COUNT static struct k_work_delayable shadow_update_work; static struct k_work_delayable connect_work; static struct k_work shadow_update_version_work; static bool cloud_connected; static K_SEM_DEFINE(lte_connected, 0, 1); static K_SEM_DEFINE(date_time_obtained, 0, 1); static int json_add_obj(cJSON *parent, const char *str, cJSON *item) { cJSON_AddItemToObject(parent, str, item); return 0; } static int json_add_str(cJSON *parent, const char *str, const char *item) { cJSON *json_str; json_str = cJSON_CreateString(item); if (json_str == NULL) { return -ENOMEM; } return json_add_obj(parent, str, json_str); } static int json_add_number(cJSON *parent, const char *str, double item) { cJSON *json_num; json_num = cJSON_CreateNumber(item); if (json_num == NULL) { return -ENOMEM; } return json_add_obj(parent, str, json_num); } static int shadow_update(bool version_number_include) { int err; char *message; int64_t message_ts = 0; int mV = 0; int raw = 0; LOG_INF("Getting date and time"); err = date_time_now(&message_ts); if (err) { LOG_ERR("date_time_now, error: %d", err); return err; } LOG_INF("Trying to read from the ADC"); err = get_adc_reading(&mV, &raw); if (err) { LOG_ERR("get_adc_reading, error: %d", err); return err; } cJSON *root_obj = cJSON_CreateObject(); cJSON *state_obj = cJSON_CreateObject(); cJSON *reported_obj = cJSON_CreateObject(); if (root_obj == NULL || state_obj == NULL || reported_obj == NULL) { cJSON_Delete(root_obj); cJSON_Delete(state_obj); cJSON_Delete(reported_obj); err = -ENOMEM; return err; } if (version_number_include) { err = json_add_str(reported_obj, "app_version", CONFIG_AWS_IOT_SAMPLE_APP_VERSION); } else { err = 0; } err += json_add_number(reported_obj, "raw adc reading", raw); err += json_add_number(reported_obj, "converted adc reading mV", mV); err += json_add_number(reported_obj, "ts", message_ts); err += json_add_obj(state_obj, "reported", reported_obj); err += json_add_obj(root_obj, "state", state_obj); if (err) { LOG_ERR("json_add, error: %d", err); goto cleanup; } message = cJSON_Print(root_obj); if (message == NULL) { LOG_ERR("cJSON_Print, error: returned NULL"); err = -ENOMEM; goto cleanup; } struct aws_iot_data tx_data = { .qos = MQTT_QOS_0_AT_MOST_ONCE, .topic.type = AWS_IOT_SHADOW_TOPIC_UPDATE, .ptr = message, .len = strlen(message) }; LOG_INF("Publishing: %s to AWS IoT broker", message); err = aws_iot_send(&tx_data); if (err) { LOG_ERR("aws_iot_send, error: %d", err); } cJSON_FreeString(message); cleanup: cJSON_Delete(root_obj); return err; } static void connect_work_fn(struct k_work *work) { int err; if (cloud_connected) { return; } err = aws_iot_connect(NULL); if (err) { LOG_ERR("aws_iot_connect, error: %d", err); } LOG_INF("Next connection retry in %d seconds", CONFIG_AWS_IOT_SAMPLE_CONNECTION_RETRY_TIMEOUT_SECONDS); k_work_schedule(&connect_work, K_SECONDS(CONFIG_AWS_IOT_SAMPLE_CONNECTION_RETRY_TIMEOUT_SECONDS)); } static void shadow_update_work_fn(struct k_work *work) { int err; if (!cloud_connected) { return; } err = shadow_update(false); if (err) { LOG_ERR("shadow_update, error: %d", err); } LOG_INF("Next data publication in %d seconds", CONFIG_AWS_IOT_SAMPLE_PUBLICATION_INTERVAL_SECONDS); k_work_schedule(&shadow_update_work, K_SECONDS(CONFIG_AWS_IOT_SAMPLE_PUBLICATION_INTERVAL_SECONDS)); } static void shadow_update_version_work_fn(struct k_work *work) { int err; err = shadow_update(true); if (err) { LOG_ERR("shadow_update, error: %d", err); } } static void print_received_data(const char *buf, const char *topic, size_t topic_len) { char *str = NULL; cJSON *root_obj = NULL; root_obj = cJSON_Parse(buf); if (root_obj == NULL) { LOG_ERR("cJSON Parse failure"); return; } str = cJSON_Print(root_obj); if (str == NULL) { LOG_ERR("Failed to print JSON object"); goto clean_exit; } LOG_INF("Data received from AWS IoT console: Topic: %.*s Message: %s", topic_len, topic, str); cJSON_FreeString(str); clean_exit: cJSON_Delete(root_obj); } void aws_iot_event_handler(const struct aws_iot_evt *const evt) { switch (evt->type) { case AWS_IOT_EVT_CONNECTING: LOG_INF("AWS_IOT_EVT_CONNECTING"); break; case AWS_IOT_EVT_CONNECTED: LOG_INF("AWS_IOT_EVT_CONNECTED"); cloud_connected = true; /* This may fail if the work item is already being processed, * but in such case, the next time the work handler is executed, * it will exit after checking the above flag and the work will * not be scheduled again. */ (void)k_work_cancel_delayable(&connect_work); if (evt->data.persistent_session) { LOG_INF("Persistent session enabled"); } #if defined(CONFIG_NRF_MODEM_LIB) /** Successfully connected to AWS IoT broker, mark image as * working to avoid reverting to the former image upon reboot. */ boot_write_img_confirmed(); #endif /** Send version number to AWS IoT broker to verify that the * FOTA update worked. */ k_work_submit(&shadow_update_version_work); /** Start sequential shadow data updates. */ k_work_schedule(&shadow_update_work, K_SECONDS(CONFIG_AWS_IOT_SAMPLE_PUBLICATION_INTERVAL_SECONDS)); #if defined(CONFIG_NRF_MODEM_LIB) int err = lte_lc_psm_req(true); if (err) { LOG_ERR("Requesting PSM failed, error: %d", err); } #endif break; case AWS_IOT_EVT_READY: LOG_INF("AWS_IOT_EVT_READY"); break; case AWS_IOT_EVT_DISCONNECTED: LOG_INF("AWS_IOT_EVT_DISCONNECTED"); cloud_connected = false; /* This may fail if the work item is already being processed, * but in such case, the next time the work handler is executed, * it will exit after checking the above flag and the work will * not be scheduled again. */ (void)k_work_cancel_delayable(&shadow_update_work); k_work_schedule(&connect_work, K_NO_WAIT); break; case AWS_IOT_EVT_DATA_RECEIVED: LOG_INF("AWS_IOT_EVT_DATA_RECEIVED"); print_received_data(evt->data.msg.ptr, evt->data.msg.topic.str, evt->data.msg.topic.len); break; case AWS_IOT_EVT_PUBACK: LOG_INF("AWS_IOT_EVT_PUBACK, message ID: %d", evt->data.message_id); break; case AWS_IOT_EVT_FOTA_START: LOG_INF("AWS_IOT_EVT_FOTA_START"); break; case AWS_IOT_EVT_FOTA_ERASE_PENDING: LOG_INF("AWS_IOT_EVT_FOTA_ERASE_PENDING"); LOG_INF("Disconnect LTE link or reboot"); #if defined(CONFIG_NRF_MODEM_LIB) err = lte_lc_offline(); if (err) { LOG_ERR("Error disconnecting from LTE"); } #endif break; case AWS_IOT_EVT_FOTA_ERASE_DONE: LOG_INF("AWS_FOTA_EVT_ERASE_DONE"); LOG_INF("Reconnecting the LTE link"); #if defined(CONFIG_NRF_MODEM_LIB) err = lte_lc_connect(); if (err) { LOG_ERR("Error connecting to LTE"); } #endif break; case AWS_IOT_EVT_FOTA_DONE: LOG_INF("AWS_IOT_EVT_FOTA_DONE"); LOG_INF("FOTA done, rebooting device"); aws_iot_disconnect(); sys_reboot(0); break; case AWS_IOT_EVT_FOTA_DL_PROGRESS: LOG_INF("AWS_IOT_EVT_FOTA_DL_PROGRESS, (%d%%)", evt->data.fota_progress); case AWS_IOT_EVT_ERROR: LOG_INF("AWS_IOT_EVT_ERROR, %d", evt->data.err); break; case AWS_IOT_EVT_FOTA_ERROR: LOG_INF("AWS_IOT_EVT_FOTA_ERROR"); break; default: LOG_WRN("Unknown AWS IoT event type: %d", evt->type); break; } } static void work_init(void) { k_work_init_delayable(&shadow_update_work, shadow_update_work_fn); k_work_init_delayable(&connect_work, connect_work_fn); k_work_init(&shadow_update_version_work, shadow_update_version_work_fn); } #if defined(CONFIG_NRF_MODEM_LIB) static void lte_handler(const struct lte_lc_evt *const evt) { switch (evt->type) { case LTE_LC_EVT_NW_REG_STATUS: if ((evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_HOME) && (evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_ROAMING)) { break; } LOG_INF("Network registration status: %s", evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME ? "Connected - home network" : "Connected - roaming"); k_sem_give(<e_connected); break; case LTE_LC_EVT_PSM_UPDATE: LOG_INF("PSM parameter update: TAU: %d, Active time: %d", evt->psm_cfg.tau, evt->psm_cfg.active_time); break; case LTE_LC_EVT_EDRX_UPDATE: { char log_buf[60]; ssize_t len; len = snprintf(log_buf, sizeof(log_buf), "eDRX parameter update: eDRX: %f, PTW: %f", evt->edrx_cfg.edrx, evt->edrx_cfg.ptw); if (len > 0) { LOG_INF("%s", log_buf); } break; } case LTE_LC_EVT_RRC_UPDATE: LOG_INF("RRC mode: %s", evt->rrc_mode == LTE_LC_RRC_MODE_CONNECTED ? "Connected" : "Idle"); break; case LTE_LC_EVT_CELL_UPDATE: LOG_INF("LTE cell changed: Cell ID: %d, Tracking area: %d", evt->cell.id, evt->cell.tac); break; default: break; } } static void nrf_modem_lib_dfu_handler(int err) { switch (err) { case NRF_MODEM_DFU_RESULT_OK: LOG_INF("Modem update suceeded, reboot"); sys_reboot(SYS_REBOOT_COLD); break; case NRF_MODEM_DFU_RESULT_UUID_ERROR: case NRF_MODEM_DFU_RESULT_AUTH_ERROR: LOG_INF("Modem update failed, error: %d", err); LOG_INF("Modem will use old firmware"); sys_reboot(SYS_REBOOT_COLD); break; case NRF_MODEM_DFU_RESULT_HARDWARE_ERROR: case NRF_MODEM_DFU_RESULT_INTERNAL_ERROR: LOG_INF("Modem update malfunction, error: %d, reboot", err); sys_reboot(SYS_REBOOT_COLD); break; case NRF_MODEM_DFU_RESULT_VOLTAGE_LOW: LOG_INF("Modem update cancelled due to low power, error: %d", err); LOG_INF("Please reboot once you have sufficient power for the DFU"); break; default: break; } } #endif static int app_topics_subscribe(void) { int err; static char custom_topic[75] = "my-custom-topic/example"; static char custom_topic_2[75] = "my-custom-topic/example_2"; const struct aws_iot_topic_data topics_list[APP_TOPICS_COUNT] = { [0].str = custom_topic, [0].len = strlen(custom_topic), [1].str = custom_topic_2, [1].len = strlen(custom_topic_2) }; err = aws_iot_subscription_topics_add(topics_list, ARRAY_SIZE(topics_list)); if (err) { LOG_ERR("aws_iot_subscription_topics_add, error: %d", err); } return err; } static void date_time_event_handler(const struct date_time_evt *evt) { switch (evt->type) { case DATE_TIME_OBTAINED_MODEM: /* Fall through */ case DATE_TIME_OBTAINED_NTP: /* Fall through */ case DATE_TIME_OBTAINED_EXT: LOG_INF("Date time obtained"); k_sem_give(&date_time_obtained); /* De-register handler. At this point the sample will have * date time to depend on indefinitely until a reboot occurs. */ date_time_register_handler(NULL); break; case DATE_TIME_NOT_OBTAINED: LOG_INF("DATE_TIME_NOT_OBTAINED"); break; default: LOG_ERR("Unknown event: %d", evt->type); break; } } int main(void) { int err; LOG_INF("The AWS IoT sample started, version: %s", CONFIG_AWS_IOT_SAMPLE_APP_VERSION); cJSON_Init(); #if defined(CONFIG_NRF_MODEM_LIB) err = nrf_modem_lib_init(); if (err) { LOG_ERR("Modem library initialization failed, error: %d", err); return 0; } nrf_modem_lib_dfu_handler(err); #endif #if defined(CONFIG_AWS_IOT_SAMPLE_DEVICE_ID_USE_HW_ID) char device_id[HW_ID_LEN] = { 0 }; err = hw_id_get(device_id, ARRAY_SIZE(device_id)); if (err) { LOG_ERR("Failed to retrieve device ID, error: %d", err); return 0; } struct aws_iot_config config = { .client_id = device_id, .client_id_len = strlen(device_id) }; LOG_INF("Device id: %s", device_id); err = aws_iot_init(&config, aws_iot_event_handler); #else err = aws_iot_init(NULL, aws_iot_event_handler); #endif if (err) { LOG_ERR("AWS IoT library could not be initialized, error: %d", err); } /** Subscribe to customizable non-shadow specific topics * to AWS IoT backend. */ err = app_topics_subscribe(); if (err) { LOG_ERR("Adding application specific topics failed, error: %d", err); } work_init(); #if defined(CONFIG_NRF_MODEM_LIB) err = lte_lc_init_and_connect_async(lte_handler); if (err) { LOG_ERR("Modem could not be configured, error: %d", err); return 0; } err = modem_info_init(); if (err) { LOG_ERR("Failed initializing modem info module, error: %d", err); } k_sem_take(<e_connected, K_FOREVER); #endif /* Trigger a date time update. The date_time API is used to timestamp data that is sent * to AWS IoT. */ date_time_update_async(date_time_event_handler); /* Postpone connecting to AWS IoT until date time has been obtained. */ k_sem_take(&date_time_obtained, K_FOREVER); k_work_schedule(&connect_work, K_NO_WAIT); return 0; }
#include <zephyr/kernel.h> #include <zephyr/logging/log.h> #include <zephyr/device.h> #include <zephyr/drivers/gpio.h> #include <zephyr/drivers/adc.h> #include <stdio.h> #include <string.h> //ADC #include <hal/nrf_saadc.h> #define ADC_DEVICE_NODE DT_NODELABEL(adc) #define ADC_RESOLUTION 12 #define ADC_GAIN ADC_GAIN_1_6 #define ADC_REFERENCE ADC_REF_INTERNAL #define ADC_ACQUISITION_TIME ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10) #define ADC_1ST_CHANNEL_ID 1 #define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN1 #define ADC_2ND_CHANNEL_ID 2 #define ADC_2ND_CHANNEL_INPUT NRF_SAADC_INPUT_AIN2 #define SLEEP_TIME_MS 700 static const struct device *adc_dev = DEVICE_DT_GET(ADC_DEVICE_NODE); static const struct adc_channel_cfg m_1st_channel_cfg = { .gain = ADC_GAIN, .reference = ADC_REFERENCE, .acquisition_time = ADC_ACQUISITION_TIME, .channel_id = ADC_1ST_CHANNEL_ID, .differential = 1, #if defined(CONFIG_ADC_CONFIGURABLE_INPUTS) .input_positive = ADC_1ST_CHANNEL_INPUT, .input_negative = ADC_2ND_CHANNEL_INPUT, #endif }; #define BUFFER_SIZE 1 static int16_t m_sample_buffer[BUFFER_SIZE]; static int adc_sample(int *volt, int *raw) { int ret; const struct adc_sequence sequence = { .channels = BIT(ADC_1ST_CHANNEL_ID), .buffer = m_sample_buffer, .buffer_size = sizeof(m_sample_buffer), .resolution = ADC_RESOLUTION, }; if (!adc_dev) { return -1; } ret = adc_read(adc_dev, &sequence); int32_t adc_voltage = m_sample_buffer[0]; ret = adc_raw_to_millivolts(adc_ref_internal(adc_dev), ADC_GAIN, ADC_RESOLUTION-1, &adc_voltage); if (ret) { printk("raw_to_mili Broke!"); return ret; } *raw = m_sample_buffer[0]; *volt = adc_voltage; return ret; } int get_adc_reading(int *milivolt, int *raw) { struct gpio_dt_spec p17 = GPIO_DT_SPEC_GET(DT_NODELABEL(led0), gpios); struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(DT_ALIAS(led1), gpios); if (!device_is_ready(p17.port)) { return -1; } if (!device_is_ready(led1.port)) { return -1; } int err; gpio_pin_configure_dt(&p17, GPIO_OUTPUT); gpio_pin_configure_dt(&led1, GPIO_OUTPUT_ACTIVE); err = gpio_pin_set_dt(&p17, 1); err = gpio_pin_set_dt(&led1, 1); if (err) { return err; } err = adc_channel_setup(adc_dev, &m_1st_channel_cfg); if (err) { return err; } for (int i = 0; i <= 20; i++) { err = adc_sample(milivolt, raw); if (err) { return err; } k_msleep(SLEEP_TIME_MS); } gpio_pin_set_dt(&p17, 0); gpio_pin_set_dt(&led1, 0); return 0; }