NRF52840 AD7124 Code
Revision as of 03:22, 11 January 2019 by Paul (talk | contribs) (Paul moved page NRF52840 AD7124 Development Code to NRF52840 AD7124 Code)
Inital nRF52840 code that talks to the AD7124-8
/** * Copyright (c) 2015 - 2017, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "nrf_drv_spi.h" #include "app_util_platform.h" #include "nrf_gpio.h" #include "nrf_delay.h" #include "boards.h" #include "app_error.h" #include <string.h> #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #include "SEGGER_RTT.h" #define SPI_INSTANCE 0 /**< SPI instance index. */ static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); /**< SPI instance. */ static volatile bool spi_xfer_done; /**< Flag used to indicate that SPI instance completed the transfer. */ /* AD7124 parameters */ char FS[2] = { 0x01, 0x40 }; /* Filter Select (FS) default: 320 */ char PGA = 0x07; /* PGA default: 128 */ char AINM = 0x06; /* Negative analog input: 6 */ char AINP = 0x07; /* Positive analog input: 7 */ enum { LOW_POWER=0x00, MEDIUM_POWER=0x40, HIGH_POWER=0x80 } power_mode = HIGH_POWER; int data_register=0; int return_code = 0; char wrBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; char rdBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; int number_active_channels=1; int number_of_filtered_samples = 0; int data_array[64]; int number_of_samples = 16; /* Number of data reads to average */ int sum = 0; int sample_counter = 0; /* ***************************************************************************************** * * reset_AD7124 * * sends 64 ones (eight 0xFF) to the AD7124 to reset it * * **************************************************************************************** */ void reset_AD7124 ( void ) { SEGGER_RTT_WriteString(0, "reset_AD7124.\n"); /* reset AD7124 by writing 64 ones (eight 0xFF) */ uint8_t wrBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint8_t rdBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // memset(m_rx_buf, 0, m_length); spi_xfer_done = false; nrf_delay_ms(10); APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 8, rdBuf, 8)); /* check reset by reading device ID code */ wrBuf[0]= 0x45; nrf_delay_ms(10); APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 2, rdBuf, 2)); SEGGER_RTT_printf(0, "Device ID Code: 0x%02x\n", rdBuf[1]); if ( rdBuf[1] != 0x14 ) { bsp_board_led_invert(BSP_BOARD_LED_3); SEGGER_RTT_printf(0, "Reset failed: 0x%02x 0x%02x\n", rdBuf[0], rdBuf[1]); } } /* ****************************************************************************************** * * initialize_AD7124 * * turns of default number_active_channel * turns on * sets the filter * * **************************************************************************************** */ void initialize_AD7124 ( void ) { uint8_t wrBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t rdBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; SEGGER_RTT_WriteString(0, "Starting initialize_AD7124.\n"); wrBuf[0]= 0x09; wrBuf[1]= 0x00; wrBuf[2]= 0x01; /* Turn off channel_0 (on by default) */ APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 3, rdBuf, 3)); SEGGER_RTT_WriteString(0, "Turned off channel 0.\n"); //wrBuf[1] = ( AIMP & 0x18 ) >> 3 ; wrBuf[0]= 0x0a; wrBuf[1] = (( AINP >> 3) & 0x07 ) | 0x80; wrBuf[2] = (( AINP & 0x07 ) << 5) | ( AINM & 0x1F ); SEGGER_RTT_printf(0, "Write buffers: 0x%02x 0x%02x 0x%02x\n", wrBuf[0], wrBuf[1], wrBuf[2]); APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 3, rdBuf, 3)); SEGGER_RTT_WriteString(0, "Set up AINP.\n"); wrBuf[0]= 0x19; wrBuf[1]= 0x08; wrBuf[2]= 0x7F; APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 3, rdBuf, 3)); wrBuf[0]= 0x21; wrBuf[1]= 0x06; wrBuf[2]= FS[0]; wrBuf[3]= FS[1]; /* Set the Filter Select bits */ APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 4, rdBuf, 4)); SEGGER_RTT_WriteString(0, "Set up FS bits.\n"); wrBuf[0]= 0x07; wrBuf[1]= 0x03; wrBuf[2]= 0xF0; wrBuf[3]= 0x38; APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 4, rdBuf, 4)); } /* ****************************************************************************************** * * wait_for_AD7124_ready * * waits for AD7124 to finish conversion by testing the busy busy bit * if it times out, it return busy (1) * waiting set the how long it will wait for the conversion before it times out * * **************************************************************************************** */ uint8_t wait_for_AD7124_ready(void) { uint8_t wrBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t rdBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; unsigned int waiting=10000; uint8_t busy = 1; while( busy && waiting ) { /* Read the Status Register */ wrBuf[0]= 0x40; APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 2, rdBuf, 2)); busy = rdBuf[1] & 0x80 ; /* Test the Not Ready bit */ nrf_delay_ms(1); /* wait 0.1 msec */ waiting--; } // SEGGER_RTT_printf(0, "waiting: %d\n", waiting); return busy; } /* ****************************************************************************************** * * read_AD7124 * * turn on load cell excitation * start continuous data conversion * Read the data register * Read the error register * Loop for the number of samples or untill have tried 128 times * turn off load cell excitation * * **************************************************************************************** */ void read_AD7124(void) { uint8_t wrBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t rdBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; int i = 0; int read_counter = 0; SEGGER_RTT_WriteString(0, "read_AD7124.\n"); NRF_LOG_FLUSH(); /* turn on load cell excitation using PDSW Power Down Switch */ wrBuf[0]= 0x03; wrBuf[1]= 0x00; wrBuf[2]= 0x80; wrBuf[3]= 0x00; APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 4, rdBuf, 4)); SEGGER_RTT_printf(0, "Load Cell turned ON.\n"); /* start data conversion, Continuous conversion mode 00 0084 ADC Control High power, Mode 0*/ wrBuf[0]= 0x01; wrBuf[1]= 0x06; wrBuf[2]= power_mode; APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 3, rdBuf, 3)); SEGGER_RTT_printf(0, "Data conversion started.\n"); wrBuf[0]= 0x41; wrBuf[1]= 0x00; wrBuf[2]= 0x00; nrf_delay_ms(100); APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 3, rdBuf, 3)); SEGGER_RTT_printf(0, "read from controll register.\n"); SEGGER_RTT_printf(0, "Control register: 0x%02x 0x%02x 0x%02x\n", rdBuf[0], rdBuf[1], rdBuf[2]); sum=0; sample_counter=0; read_counter = 0; while ( read_counter < 128 && sample_counter < number_of_samples ) { for ( i=0; i< number_active_channels; i++ ) { if ( !wait_for_AD7124_ready() ) { /* Read the data register */ wrBuf[0]= 0x42; APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 5, rdBuf, 5)); data_register = (rdBuf[1] << 16) | (rdBuf[2] << 8) | (rdBuf[3]); SEGGER_RTT_printf(0, "Data register: 0x%02x 0x%02x 0x%02x\n", rdBuf[1], rdBuf[2], rdBuf[3]); /* Read the error register */ wrBuf[0]= 0x46; APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 4, rdBuf, 4)); /* Check for errors */ // SEGGER_RTT_printf(0, "Error register: 0x%02x 0x%02x 0x%02x\n", rdBuf[1], rdBuf[2], rdBuf[3]); if ( (rdBuf[1] | rdBuf[2] | rdBuf[3]) == 0 ) /* if no errors, use data to calculate average */ { data_array[sample_counter] = data_register; sum += data_register; sample_counter++; } } } read_counter++; } /* turn off load cell excitation using PDSW Power Down Switch */ wrBuf[0]= 0x03; wrBuf[1]= 0x00; wrBuf[2]= 0x00; wrBuf[3]= 0x00; APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wrBuf, 4, rdBuf, 4)); SEGGER_RTT_printf(0, "Load Cell turned OFF.\n"); //if (sample_counter == 0) return 5; number_of_filtered_samples = sample_counter; } /************************* median_select ********************************* * * from http://ndevilla.free.fr/median/median/ * This Quickselect routine is based on the algorithm described in * "Numerical recipes in C", Second Edition, * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5 * This code by Nicolas Devillard - 1998. Public domain. * ***************************************************************************/ #define ELEM_SWAP(a,b) { register int t=(a);(a)=(b);(b)=t; } int median_select(int arr[], int n) { int low, high; int median; int middle, ll, hh; low = 0 ; high = n-1 ; median = (low + high) / 2; for (;;) { if (high <= low) /* One element only */ return arr[median]; if (high == low + 1) { /* Two elements only */ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]); return arr[median]; } /* Find median of low, middle and high items; swap into position low */ middle = (low + high) / 2; if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]); if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]); if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]); /* Swap low item (now in position middle) into position (low+1) */ ELEM_SWAP(arr[middle], arr[low+1]); /* Nibble from each end towards middle, swapping items when stuck */ ll = low + 1; hh = high; for (;;) { do ll++; while (arr[low] > arr[ll]); do hh--; while (arr[hh] > arr[low]); if (hh < ll) break; ELEM_SWAP(arr[ll], arr[hh]); } /* Swap middle item (in position low) back into correct position */ ELEM_SWAP(arr[low], arr[hh]); /* Re-set active partition */ if (hh <= median) low = ll; if (hh >= median) high = hh - 1; } } #undef ELEM_SWAP int main(void) { char buffer[50]; int j=0; bsp_board_leds_init(); APP_ERROR_CHECK(NRF_LOG_INIT(NULL)); NRF_LOG_DEFAULT_BACKENDS_INIT(); SEGGER_RTT_printf(0, "\n\nStarted main routine ...\n"); NRF_LOG_INFO("SPI example."); nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; spi_config.frequency = NRF_SPI_FREQ_4M; spi_config.mode = NRF_DRV_SPI_MODE_3; spi_config.ss_pin = 29; // SPI_SS_PIN; // 29 spi_config.miso_pin = 28; // SPI_MISO_PIN; // 28 spi_config.mosi_pin = 4; // SPI_MOSI_PIN; // 4 spi_config.sck_pin = 3; // SPI_SCK_PIN; // 3 // APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL)); APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, NULL, NULL)); SEGGER_RTT_printf(0, "SPI Initialized.\n"); // SEGGER_RTT_WriteString(0, "SPI Initialized.\n"); reset_AD7124(); initialize_AD7124(); while (1) { bsp_board_led_invert(BSP_BOARD_LED_0); // reset_AD7124(); // initialize_AD7124(); read_AD7124(); bsp_board_led_invert(BSP_BOARD_LED_0); int median = median_select( data_array, sample_counter ); sum = 0; number_of_filtered_samples = 0; /* set limits for outliers */ int high_limit = median * 1.00002; int low_limit = median * .99998; /* Test for outliers and throw them away */ for ( j=0; j<sample_counter; j++ ) { if ( data_array[j] < high_limit && data_array[j] > low_limit ) { number_of_filtered_samples++; sum += data_array[j]; // printf ("data_array: %d less median: %d\n", data_array[j], data_array[j] - median); } // else // printf ("OUTLIER %d less median: %d\n", data_array[j], data_array[j] - median); } if (number_of_filtered_samples == 0) return 6; /* calculate raw average */ int filtered_average = sum/number_of_filtered_samples; SEGGER_RTT_printf(0, "Filtered average: %d\n", filtered_average); // float weight = (float)(filtered_average - 8413535) * .0003375; // float weight = (float) (filtered_average * 0.0003438388) - 2892.912; // SEGGER_RTT_printf(0, "Weight: %7.3f\n", (0.0003438388 * (sum/number_of_filtered_samples)) - 2892.912 ); // float weight = (filtered_average * 0.3438388) - 2892912; float weight = (filtered_average * 0.0003438388) - 2892.912; sprintf(buffer, "Samples: %d Weight: %7.3f lb\n",number_of_filtered_samples, weight); SEGGER_RTT_printf(0, buffer); // SEGGER_RTT_WriteString(0, buffer); // SEGGER_RTT_printf(0, "weight: %d\n", weight); nrf_delay_ms(1000); } }