├── nbproject ├── private │ ├── Default.properties │ ├── CodeAssistancePathMapper.properties │ ├── private.xml │ ├── launcher.properties │ ├── configurations.xml │ ├── c_standard_headers_indexer.c │ ├── Default-build.log │ └── cpp_standard_headers_indexer.cpp └── project.xml ├── .gitignore ├── AD5593R.h ├── ADC.h ├── FDC1004.h ├── BME280.h ├── pca10040 └── s132 │ └── armgcc │ ├── mentaid.ld │ └── Makefile ├── ics43434.h ├── I2C.h ├── README.md ├── VEML6040.h ├── SPIFlash.h ├── BMA280.h ├── ADC.c ├── AD5593R.c ├── VEML6040.c ├── I2C.c ├── FDC1004.c ├── BMA280.c ├── ble_ma.h ├── BME280.c ├── ics43434.c ├── app_pwm.h ├── SPIFlash.c ├── ble_ma.c └── app_pwm.c /nbproject/private/Default.properties: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /nbproject/private/CodeAssistancePathMapper.properties: -------------------------------------------------------------------------------- 1 | # Automatic path mapper. CRC = 1 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.o 3 | *.d 4 | *.bin 5 | *.hex 6 | *.map 7 | *.out 8 | *.in -------------------------------------------------------------------------------- /AD5593R.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MA_AD5593R_H_ 3 | #define MA_AD5593R_H_ 4 | 5 | #include "I2C.h" 6 | #include "SEGGER_RTT.h" 7 | 8 | void AD5593R_Turn_On( void ); 9 | void AD5593R_Configure( void ); 10 | void AD5593R_Get_Data( float * result) ; 11 | 12 | #endif /* MA_AD5593R_H_ */ 13 | -------------------------------------------------------------------------------- /ADC.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MA_ADC_H__ 3 | #define MA_ADC_H__ 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include "nrf_drv_saadc.h" 10 | void ADC_init(void); 11 | int16_t Current_VBATT( void ); 12 | void ADC_callback(nrf_drv_saadc_evt_t const * p_event); 13 | 14 | #ifdef __cplusplus 15 | } 16 | #endif 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /FDC1004.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MA_FDC1004_H_ 3 | #define MA_FDC1004_H_ 4 | 5 | #include "I2C.h" 6 | #include "SEGGER_RTT.h" 7 | 8 | void FDC1004_Configure( void ); 9 | void FDC1004_Turn_On( void ); 10 | void FDC1004_Get_Data( float * result) ; 11 | float ConvertFDCToFloat( uint8_t * dM, uint8_t * dL ); 12 | 13 | #endif /* MA_FDC1004_H_ */ 14 | -------------------------------------------------------------------------------- /BME280.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MA_BME280_H_ 3 | #define MA_BME280_H_ 4 | 5 | #include "I2C.h" 6 | #include "app_error.h" 7 | #include "nrf_delay.h" 8 | #include "SEGGER_RTT.h" 9 | 10 | void BME280_Configure( uint8_t address ); 11 | void BME280_Turn_On( void ); 12 | void BME280_Get_Data(int32_t * resultPTH); 13 | 14 | int32_t BME280_Compensate_T(int32_t t_fine); 15 | uint32_t BME280_Compensate_P(int32_t adc_P, int32_t t_fine); 16 | uint32_t BME280_Compensate_H(int32_t adc_H, int32_t t_fine); 17 | 18 | #endif /* MA_BME280_H_ */ 19 | -------------------------------------------------------------------------------- /pca10040/s132/armgcc/mentaid.ld: -------------------------------------------------------------------------------- 1 | /* Linker script to configure memory regions. */ 2 | 3 | SEARCH_DIR(.) 4 | GROUP(-lgcc -lc -lnosys) 5 | 6 | MEMORY 7 | { 8 | FLASH (rx) : ORIGIN = 0x1f000, LENGTH = 0x61000 9 | RAM (rwx) : ORIGIN = 0x20002558, LENGTH = 0xdaa8 10 | } 11 | 12 | SECTIONS 13 | { 14 | .fs_data : 15 | { 16 | PROVIDE(__start_fs_data = .); 17 | KEEP(*(.fs_data)) 18 | PROVIDE(__stop_fs_data = .); 19 | } > RAM 20 | } INSERT AFTER .data; 21 | 22 | SECTIONS 23 | { 24 | .pwr_mgmt_data : 25 | { 26 | PROVIDE(__start_pwr_mgmt_data = .); 27 | KEEP(*(SORT(.pwr_mgmt_data*))) 28 | PROVIDE(__stop_pwr_mgmt_data = .); 29 | } > FLASH 30 | } INSERT AFTER .text 31 | 32 | INCLUDE "nrf5x_common.ld" 33 | -------------------------------------------------------------------------------- /ics43434.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MA_ICS43434_H_ 3 | #define MA_ICS43434_H_ 4 | 5 | #include "arm_const_structs.h" 6 | 7 | #define I2S_BUFFER_SIZE 2048 // Data handler is called when I2S data bufffer contains (I2S_BUFFER_SIZE/2) 32bit words 8 | #define AUDIO_RATE 10000L // Audio frame rate; 16000000/AUDIO_RATE must be an integral multiple of 64! 9 | #define FPU_EXCEPTION_MASK 0x0000009F // FPU exception mask used to clear exceptions in FPSCR register 10 | 11 | typedef struct 12 | { 13 | float max; 14 | float avg; 15 | float32_t freq[3]; 16 | float32_t complex_mag[3]; 17 | } fft_results_t; 18 | 19 | void ICS_Sample(void); 20 | void ICS_Configure(void); 21 | void ICS_Get_Data(float * dest); 22 | 23 | #endif /* MA_ICS43434_H_ */ 24 | -------------------------------------------------------------------------------- /I2C.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MA_I2C_H__ 3 | #define MA_I2C_H__ 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include "nrf_drv_twi.h" 10 | #include "app_error.h" //for APP_ERROR_CHECK(err_code); 11 | #include "SEGGER_RTT.h" 12 | 13 | void I2C_init( void ); 14 | 15 | void writeByte( uint8_t address, uint8_t subAddress, uint8_t data); 16 | 17 | void writeBytes(uint8_t address, uint8_t * data, uint8_t n_bytes); 18 | 19 | void readBytes( uint8_t address, uint8_t subAddress, uint8_t * dest, uint8_t n_bytes); 20 | 21 | uint8_t readByte(uint8_t address, uint8_t subAddress); 22 | 23 | void I2C_handler(nrf_drv_twi_evt_t const * p_event, void * p_context); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | 29 | #endif /* MA_I2C_H__ */ 30 | -------------------------------------------------------------------------------- /nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.netbeans.modules.cnd.makeproject 4 | 5 | 6 | mentaid 7 | c 8 | 9 | h 10 | UTF-8 11 | 12 | 13 | . 14 | 15 | 16 | 17 | Default 18 | 0 19 | 20 | 21 | 22 | false 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MENTAID firmware 2 | 3 | This is the firmware for a Stanford University-funded wearable. The wearable collects information from about 10 sensors, logs this information, and can send it into the cloud if and when the wearer wishes to do so. The iOS code is also available, please see https://github.com/jliphard/wearable_nRF52_iOS. The code is under very active development, so expect things to change rapidly without notice. 4 | 5 | 1/ The ADC, I2C/TWI, BME280, and the SPI FLASH are functional and tested. 6 | 7 | 2/ The goal right now is to have the device: 8 | 9 | _Goal 1_ - Baseline/robust datalogging 10 | *Sample all sensors once per min 11 | *Write the data to flash in units of 256 bytes 12 | *Sleep for most of the time (i.e. between the sampling events) 13 | *Do that until it drains the battery. 14 | 15 | _Goal 2_ - Minimal BLE functionality. Upon system start, advertize BLE for 100 secs. If connect, then allow iOS BLE app to send commands, such as Erase Memory, or Upload all data. If not connect, just datalog as in use case 1. Once BLE connection drops, begin to datalog. 16 | 17 | _Goal 3_ - Get time/date/velocity from iPhone once in while to facilitate data analysis. Key for the GPS is velocity, since that helps us to understand if the wearer is cycling, driving, walking and so forth. Out of privacy concerns, we do not save or transmit GPS lat/lon location data. 18 | -------------------------------------------------------------------------------- /nbproject/private/private.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 6 | 7 | 0 8 | 0 9 | 10 | 11 | 12 | 13 | file:/Users/janliphardt/Documents/GitHub/wearable_nRF52_Firmware/main.c 14 | file:/Users/janliphardt/Documents/GitHub/wearable_nRF52_Firmware/VEML6040.c 15 | file:/Users/janliphardt/Documents/GitHub/wearable_nRF52_Firmware/ics43434.c 16 | file:/Users/janliphardt/Documents/GitHub/wearable_nRF52_Firmware/ics43434.h 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /nbproject/private/launcher.properties: -------------------------------------------------------------------------------- 1 | # Launchers File syntax: 2 | # 3 | # [Must-have property line] 4 | # launcher1.runCommand= 5 | # [Optional extra properties] 6 | # launcher1.displayName= 7 | # launcher1.hide= 8 | # launcher1.buildCommand= 9 | # launcher1.runDir= 10 | # launcher1.runInOwnTab= 11 | # launcher1.symbolFiles= 12 | # launcher1.env.= 13 | # (If this value is quoted with ` it is handled as a native command which execution result will become the value) 14 | # [Common launcher properties] 15 | # common.runDir= 16 | # (This value is overwritten by a launcher specific runDir value if the latter exists) 17 | # common.env.= 18 | # (Environment variables from common launcher are merged with launcher specific variables) 19 | # common.symbolFiles= 20 | # (This value is overwritten by a launcher specific symbolFiles value if the latter exists) 21 | # 22 | # In runDir, symbolFiles and env fields you can use these macroses: 23 | # ${PROJECT_DIR} - project directory absolute path 24 | # ${OUTPUT_PATH} - linker output path (relative to project directory path) 25 | # ${OUTPUT_BASENAME}- linker output filename 26 | # ${TESTDIR} - test files directory (relative to project directory path) 27 | # ${OBJECTDIR} - object files directory (relative to project directory path) 28 | # ${CND_DISTDIR} - distribution directory (relative to project directory path) 29 | # ${CND_BUILDDIR} - build directory (relative to project directory path) 30 | # ${CND_PLATFORM} - platform name 31 | # ${CND_CONF} - configuration name 32 | # ${CND_DLIB_EXT} - dynamic library extension 33 | # 34 | # All the project launchers must be listed in the file! 35 | # 36 | # launcher1.runCommand=... 37 | # launcher2.runCommand=... 38 | # ... 39 | # common.runDir=... 40 | # common.env.KEY=VALUE 41 | 42 | # launcher1.runCommand= -------------------------------------------------------------------------------- /VEML6040.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * The code is modified from a reference implementation by Kris Winer 8 | * (tleracorp@gmail.com) 9 | * Copyright (c) 2017, Tlera Corporation 10 | * The license terms of the TLERACORP material are: 11 | * "Library may be used freely and without limit with attribution." 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 25 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 30 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #ifndef MA_VEML6040_H_ 37 | #define MA_VEML6040_H_ 38 | 39 | #include "I2C.h" 40 | #include "app_error.h" 41 | #include "nrf_delay.h" 42 | #include "SEGGER_RTT.h" 43 | 44 | void VEML6040_Turn_On( void ); 45 | void VEML6040_Turn_Off( void ); 46 | void VEML6040_Get_Data(int16_t * dest); 47 | 48 | #endif /* MA_VEML6040_ */ 49 | -------------------------------------------------------------------------------- /SPIFlash.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 24 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef SPIFlash_h 31 | #define SPIFlash_h 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | #include 38 | #include "nrf_drv_spi.h" 39 | #include "app_error.h" 40 | 41 | void FLASH_Init( void ); 42 | void FLASH_Print_ID( void ); 43 | uint16_t FLASH_Get_First_Available_Location( void ); 44 | void FLASH_Write_Record( uint8_t wp[] ); 45 | uint8_t * FLASH_Page_Read( uint16_t pageN ); 46 | void FLASH_Line_Read( uint16_t lineN, uint8_t *line ); 47 | void FLASH_Erase( void ); 48 | void FLASH_Page_Write( uint16_t pageN, uint8_t *wp ); 49 | bool FLASH_Set_Write_Enable( void ); 50 | bool FLASH_Page_Is_Empty( uint16_t pageN ); 51 | int page_to_address( int pn ); 52 | int address_to_page( int addr ); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif /* SPIFlash_h */ 59 | 60 | -------------------------------------------------------------------------------- /BMA280.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * The code is modified from a reference implementation by Kris Winer 8 | * (tleracorp@gmail.com) 9 | * Copyright (c) 2017, Tlera Corporation 10 | * The license terms of the TLERACORP material are: 11 | * "Library may be used freely and without limit with attribution." 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 25 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 30 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #ifndef MA_BMA280_H_ 37 | #define MA_BMA280_H_ 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | #include "I2C.h" 44 | #include "app_error.h" 45 | #include "nrf_delay.h" 46 | #include "SEGGER_RTT.h" 47 | 48 | void BMA280_Turn_On_Fast( void ); 49 | void BMA280_Turn_On_Slow( void ); 50 | void BMA280_Turn_Off( void ); 51 | void BMA280_Get_Data(int16_t * dest); 52 | void BMA280_Calibrate( void ); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif /* MA_BMA280_H_ */ 59 | -------------------------------------------------------------------------------- /ADC.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ADC.h" 3 | 4 | #define ADC_SAMPLES_IN_BUFFER 1 5 | static nrf_saadc_value_t m_buffer[ADC_SAMPLES_IN_BUFFER]; 6 | float VBATT = 0.0; 7 | static int16_t batteryVoltage = 0; 8 | 9 | /* 10 | 5, // AIN3 (P0.05) 11 | 2, // AIN0 (P0.02) 12 | VBAT = (127.0f/100.0f) * 3.30f * ((float)analogRead(VbatMon))/4095.0f; //actual battery voltage 13 | */ 14 | 15 | void ADC_init(void) 16 | { 17 | ret_code_t err_code; 18 | 19 | nrf_saadc_channel_config_t channel_config = 20 | NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4); 21 | /* 22 | nrf_saadc_config_t adc_config; 23 | adc_config.resolution = NRF_SAADC_RESOLUTION_8BIT; 24 | adc_config.buffer = m_buffer; 25 | adc_config.buffer_size = ADC_SAMPLES_IN_BUFFER; 26 | adc_config.oversample = ; 27 | 28 | nrf_saadc_channel_config_t channel_0_config; 29 | channel_0_config.resistor_p = NRF_SAADC_RESISTOR_DISABLED; 30 | channel_0_config.resistor_n = NRF_SAADC_RESISTOR_DISABLED; 31 | channel_0_config.gain = NRF_SAADC_GAIN1_6; 32 | channel_0_config.reference = NRF_SAADC_REFERENCE_INTERNAL; 33 | channel_0_config.acq_time = NRF_SAADC_ACQTIME_10US; 34 | channel_0_config.mode = NRF_SAADC_MODE_SINGLE_ENDED; 35 | channel_0_config.pin_p = NRF_SAADC_INPUT_VDD; 36 | channel_0_config.pin_n = NRF_SAADC_INPUT_DISABLED; 37 | */ 38 | 39 | //channel_config. 40 | //nrf_saadc_resolution_set( NRF_SAADC_RESOLUTION_8BIT ); 41 | //APP_ERROR_CHECK(err_code); 42 | //NRF_SAADC_RESOLUTION_12BIT 43 | 44 | err_code = nrf_drv_saadc_init(NULL, ADC_callback); 45 | APP_ERROR_CHECK(err_code); 46 | 47 | err_code = nrf_drv_saadc_channel_init(0, &channel_config); 48 | APP_ERROR_CHECK(err_code); 49 | 50 | err_code = nrf_drv_saadc_buffer_convert(m_buffer, ADC_SAMPLES_IN_BUFFER); 51 | APP_ERROR_CHECK(err_code); 52 | } 53 | 54 | void ADC_callback(nrf_drv_saadc_evt_t const * p_event) 55 | { 56 | if (p_event->type == NRF_DRV_SAADC_EVT_DONE) 57 | { 58 | ret_code_t err_code; 59 | 60 | err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, ADC_SAMPLES_IN_BUFFER); 61 | APP_ERROR_CHECK(err_code); 62 | 63 | VBATT = ((float)p_event->data.done.p_buffer[0]) / 4096.0f; 64 | //NRF_LOG_INFO("ADC returned R: %d\r\n", p_event->data.done.p_buffer[0]); 65 | VBATT = VBATT * (139.0f/100.0f) * 3.30f; 66 | batteryVoltage = (uint16_t)(VBATT * 100.0f); 67 | } 68 | } 69 | 70 | int16_t Current_VBATT( void ) 71 | { 72 | return batteryVoltage; 73 | } 74 | -------------------------------------------------------------------------------- /AD5593R.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 24 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | /* 31 | Datasheet - 32 | http://www.analog.com/media/en/technical-documentation/data-sheets/AD5593R.pdf 33 | */ 34 | 35 | #include "AD5593R.h" 36 | 37 | #define AD5593R_ADDRESS 0x10 38 | 39 | // * @brief Function for setting active 40 | void AD5593R_Turn_On(void) 41 | { 42 | 43 | //to confirm ID let's read back the pull down configuration register = default is 0x00FF 44 | //AD5593R 45 | //readback = 0111____ 46 | //so command is 47 | //0111 0110 = 0x76 48 | //all other registers are 0 by default; only the PDCR has nonzero default useful for checcking 49 | //chip ID 50 | 51 | uint8_t devID[2]; 52 | 53 | readBytes(AD5593R_ADDRESS, 0x76, devID, 2); 54 | 55 | uint16_t devID_16; 56 | 57 | devID_16 = (uint16_t) devID[0] << 8 | devID[1]; 58 | 59 | SEGGER_RTT_printf(0, "AD5593R ID:%d Should be = 255\n", devID_16); 60 | 61 | if( devID_16 == 255 ) 62 | AD5593R_Configure(); 63 | 64 | } 65 | 66 | void AD5593R_Configure( void ) 67 | { 68 | //Depends on what you are trying to do - thousands of choices 69 | } 70 | 71 | void AD5593R_Get_Data( float * result ) 72 | { 73 | //Depends on what you are trying to do - thousands of choices 74 | } 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /nbproject/private/configurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | sdk_config.h 13 | 14 | 15 | 16 | AD5593R.c 17 | AD5593R.h 18 | ADC.c 19 | ADC.h 20 | BMA280.c 21 | BMA280.h 22 | BME280.c 23 | BME280.h 24 | FDC1004.c 25 | FDC1004.h 26 | I2C.c 27 | I2C.h 28 | SPIFlash.c 29 | SPIFlash.h 30 | VEML6040.c 31 | VEML6040.h 32 | app_pwm.c 33 | app_pwm.h 34 | ble_ma.c 35 | ble_ma.h 36 | ics43434.c 37 | ics43434.h 38 | main.c 39 | 40 | 41 | pca10040/s132/armgcc/Makefile 42 | 43 | 44 | 45 | localhost 46 | 4 47 | 48 | 49 | 50 | . 51 | ${AUTO_FOLDER} 52 | 53 | ${AUTO_FOLDER} 54 | 55 | ${MAKE} ${ITEM_NAME}.o 56 | ${AUTO_COMPILE} 57 | 58 | ${AUTO_COMPILE} 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | gdb 74 | 75 | 76 | 77 | "${OUTPUT_PATH}" 78 | make flash_softdevice flash 79 | 80 | make flash_softdevice flash 81 | pca10040/s132/armgcc 82 | false 83 | 0 84 | 0 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /VEML6040.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * The code is modified from a reference implementation by Kris Winer 8 | * (tleracorp@gmail.com) 9 | * Copyright (c) 2017, Tlera Corporation 10 | * The license terms of the TLERACORP material are: 11 | * "Library may be used freely and without limit with attribution." 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 25 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 30 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #include "VEML6040.h" 37 | 38 | // http://www.mouser.com/pdfdocs/veml6040.PDF 39 | 40 | //////////////////////////// 41 | // VEML6040 Command Codes // 42 | //////////////////////////// 43 | #define VEML6040_CONF 0x00 // command codes 44 | #define VEML6040_R_DATA 0x08 45 | #define VEML6040_G_DATA 0x09 46 | #define VEML6040_B_DATA 0x0A 47 | #define VEML6040_W_DATA 0x0B 48 | 49 | #define VEML6040_ADDRESS 0x10 50 | 51 | #define IT_40 0 // 40 ms 52 | #define IT_80 1 // 80 ms 53 | #define IT_160 2 // 160 ms 54 | #define IT_320 3 // 320 ms 55 | #define IT_640 4 // 640 ms 56 | #define IT_1280 5 // 1280 ms 57 | 58 | void VEML6040_Turn_On( void ) 59 | { 60 | uint8_t packet[3]; 61 | packet[0] = (uint8_t)VEML6040_CONF; 62 | packet[1] = (uint8_t)IT_1280 << 4; // Bit 3 must be 0, bit 0 is 0 for run and 1 for shutdown, LS Byte 63 | packet[2] = (uint8_t)0x00; 64 | writeBytes(VEML6040_ADDRESS, packet, 3); 65 | } 66 | 67 | void VEML6040_Turn_Off( void ) 68 | { 69 | uint8_t packet[3]; 70 | packet[0] = (uint8_t)VEML6040_CONF; 71 | packet[1] = (uint8_t)(IT_1280 << 4 | 0x01); // Bit 3 must be 0, bit 0 is 0 for run and 1 for shutdown, LS Byte 72 | packet[2] = (uint8_t)0x00; 73 | writeBytes(VEML6040_ADDRESS, packet, 3); 74 | } 75 | 76 | void VEML6040_Get_Data(int16_t * dest) 77 | { 78 | uint8_t rawData[2] = {0, 0}; 79 | 80 | readBytes(VEML6040_ADDRESS, VEML6040_R_DATA, rawData, 2); 81 | dest[0] = ((int16_t) rawData[1] << 8) | rawData[0]; 82 | 83 | readBytes(VEML6040_ADDRESS, VEML6040_G_DATA, rawData, 2); 84 | dest[1] = ((int16_t) rawData[1] << 8) | rawData[0]; 85 | 86 | readBytes(VEML6040_ADDRESS, VEML6040_B_DATA, rawData, 2); 87 | dest[2] = ((int16_t) rawData[1] << 8) | rawData[0]; 88 | 89 | readBytes(VEML6040_ADDRESS, VEML6040_W_DATA, rawData, 2); 90 | dest[3] = ((int16_t) rawData[1] << 8) | rawData[0]; 91 | 92 | if( SEGGER_VEML ) 93 | SEGGER_RTT_printf(0, "VEML6040:%d %d %d %d\n", dest[0], dest[1], dest[2], dest[3]); 94 | } 95 | 96 | -------------------------------------------------------------------------------- /nbproject/private/c_standard_headers_indexer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 | * 4 | * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. 5 | * 6 | * Oracle and Java are registered trademarks of Oracle and/or its affiliates. 7 | * Other names may be trademarks of their respective owners. 8 | * 9 | * The contents of this file are subject to the terms of either the GNU 10 | * General Public License Version 2 only ("GPL") or the Common 11 | * Development and Distribution License("CDDL") (collectively, the 12 | * "License"). You may not use this file except in compliance with the 13 | * License. You can obtain a copy of the License at 14 | * http://www.netbeans.org/cddl-gplv2.html 15 | * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the 16 | * specific language governing permissions and limitations under the 17 | * License. When distributing the software, include this License Header 18 | * Notice in each file and include the License file at 19 | * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this 20 | * particular file as subject to the "Classpath" exception as provided 21 | * by Oracle in the GPL Version 2 section of the License file that 22 | * accompanied this code. If applicable, add the following below the 23 | * License Header, with the fields enclosed by brackets [] replaced by 24 | * your own identifying information: 25 | * "Portions Copyrighted [year] [name of copyright owner]" 26 | * 27 | * If you wish your version of this file to be governed by only the CDDL 28 | * or only the GPL Version 2, indicate your decision by adding 29 | * "[Contributor] elects to include this software in this distribution 30 | * under the [CDDL or GPL Version 2] license." If you do not indicate a 31 | * single choice of license, a recipient has the option to distribute 32 | * your version of this file under either the CDDL, the GPL Version 2 or 33 | * to extend the choice of license to its licensees as provided above. 34 | * However, if you add GPL Version 2 code and therefore, elected the GPL 35 | * Version 2 license, then the option applies only if the new code is 36 | * made subject to such option by the copyright holder. 37 | * 38 | * Contributor(s): 39 | */ 40 | 41 | // List of standard headers was taken in http://en.cppreference.com/w/c/header 42 | 43 | #include // Conditionally compiled macro that compares its argument to zero 44 | #include // Functions to determine the type contained in character data 45 | #include // Macros reporting error conditions 46 | #include // Limits of float types 47 | #include // Sizes of basic types 48 | #include // Localization utilities 49 | #include // Common mathematics functions 50 | #include // Nonlocal jumps 51 | #include // Signal handling 52 | #include // Variable arguments 53 | #include // Common macro definitions 54 | #include // Input/output 55 | #include // String handling 56 | #include // General utilities: memory management, program utilities, string conversions, random numbers 57 | #include // Time/date utilities 58 | #include // (since C95) Alternative operator spellings 59 | #include // (since C95) Extended multibyte and wide character utilities 60 | #include // (since C95) Wide character classification and mapping utilities 61 | #ifdef _STDC_C99 62 | #include // (since C99) Complex number arithmetic 63 | #include // (since C99) Floating-point environment 64 | #include // (since C99) Format conversion of integer types 65 | #include // (since C99) Boolean type 66 | #include // (since C99) Fixed-width integer types 67 | #include // (since C99) Type-generic math (macros wrapping math.h and complex.h) 68 | #endif 69 | #ifdef _STDC_C11 70 | #include // (since C11) alignas and alignof convenience macros 71 | #include // (since C11) Atomic types 72 | #include // (since C11) noreturn convenience macros 73 | #include // (since C11) Thread library 74 | #include // (since C11) UTF-16 and UTF-32 character utilities 75 | #endif 76 | -------------------------------------------------------------------------------- /I2C.c: -------------------------------------------------------------------------------- 1 | 2 | #include "I2C.h" 3 | #include "nrf_drv_twi.h" 4 | 5 | #define NRF_LOG_MODULE_NAME "I2C" 6 | 7 | // I2C instance. 8 | #define TWI_INSTANCE_ID 0 9 | #define APP_IRQ_PRIORITY_LOW 3 //overrides definition elsewhere 10 | #define BA_SDA_PIN 5 // SDA signal pin 11 | #define BA_SCL_PIN 8 // SCL signal pin 12 | 13 | static const nrf_drv_twi_t i2c = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID); 14 | 15 | // Indicates if operation on TWI has ended. 16 | static volatile bool m_xfer_done = false; 17 | 18 | // @brief UART initialization. 19 | void I2C_init(void) 20 | { 21 | //NRF_LOG_DEBUG("twi_init(void)\r\n"); 22 | 23 | ret_code_t err_code; 24 | 25 | const nrf_drv_twi_config_t i2c_config = 26 | { 27 | .scl = BA_SCL_PIN, 28 | .sda = BA_SDA_PIN, 29 | .frequency = NRF_TWI_FREQ_100K, 30 | .interrupt_priority = APP_IRQ_PRIORITY_LOW, 31 | .clear_bus_init = false 32 | }; 33 | 34 | //last one is some kind of context - no idea what that is.... 35 | //documentation is vague/nonexistant 36 | err_code = nrf_drv_twi_init(&i2c, &i2c_config, I2C_handler, NULL); 37 | APP_ERROR_CHECK(err_code); 38 | 39 | nrf_drv_twi_enable(&i2c); 40 | 41 | //NRF_LOG_DEBUG("I2C_init(void) done\r\n"); 42 | } 43 | 44 | void writeByte(uint8_t address, uint8_t subAddress, uint8_t data) 45 | { 46 | uint8_t temp[2]; 47 | 48 | temp[0] = subAddress; 49 | temp[1] = data; 50 | 51 | ret_code_t err_code; 52 | m_xfer_done = false; 53 | err_code = nrf_drv_twi_tx(&i2c, address, &temp[0], 2, true); 54 | APP_ERROR_CHECK(err_code); 55 | while (m_xfer_done == false); //wait until end of transfer 56 | } 57 | 58 | void writeBytes(uint8_t address, uint8_t * data, uint8_t n_bytes) 59 | { 60 | ret_code_t err_code; 61 | m_xfer_done = false; 62 | err_code = nrf_drv_twi_tx(&i2c, address, data, n_bytes, false); //false = close the channel - not waiting for response 63 | APP_ERROR_CHECK(err_code); 64 | while (m_xfer_done == false); //wait until end of transfer -- seriously?? 65 | } 66 | 67 | uint8_t readByte(uint8_t address, uint8_t subAddress) 68 | { 69 | ret_code_t err_code = 0; 70 | 71 | uint8_t value; 72 | 73 | m_xfer_done = false; 74 | //NRF_LOG_DEBUG("readByte - Writing\r\n"); 75 | //last position is the transfer pending flag 76 | err_code = nrf_drv_twi_tx(&i2c, address, &subAddress, 1, true); 77 | 78 | APP_ERROR_CHECK(err_code); 79 | 80 | while (m_xfer_done == false); //wait until end of transfer 81 | 82 | if (err_code == NRF_SUCCESS) 83 | { 84 | m_xfer_done = false; 85 | //NRF_LOG_DEBUG("readByte - Reading\r\n"); 86 | err_code = nrf_drv_twi_rx(&i2c, address, &value, 1); 87 | APP_ERROR_CHECK(err_code); 88 | 89 | while (m_xfer_done == false); 90 | }; 91 | 92 | //NRF_LOG_DEBUG("readByte done, returned 0x\r\n"); 93 | //NRF_LOG_HEXDUMP_DEBUG(&value, 1); 94 | //NRF_LOG_FLUSH(); 95 | return value; 96 | } 97 | 98 | // @brief TWI events handler. 99 | void I2C_handler(nrf_drv_twi_evt_t const * p_event, void * p_context) 100 | { 101 | switch (p_event->type) 102 | { 103 | case NRF_DRV_TWI_EVT_DONE: 104 | 105 | //todo -difference between read and write??? 106 | m_xfer_done = true; 107 | 108 | if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX) 109 | { 110 | //SEGGER_RTT_WriteString(0, "Data just came back!\n"); 111 | } 112 | 113 | //NRF_LOG_DEBUG("I2C_handler responding to NRF_DRV_TWI_EVT_DONE\r\n"); 114 | break; 115 | default: 116 | break; 117 | } 118 | } 119 | 120 | //readBytes(BME280_ADDRESS_1, BME280_PRESS_MSB, 8, &rawData[0]); 121 | 122 | void readBytes(uint8_t address, uint8_t subAddress, uint8_t * dest, uint8_t n_bytes ) 123 | { 124 | ret_code_t err_code = 0; 125 | //0xF7 to 0xFE (temperature, pressure and humidity) 126 | //readBytes(BME280_ADDRESS_1, BME280_PRESS_MSB, 9, &rawData[0]); 127 | 128 | m_xfer_done = false; 129 | 130 | err_code = nrf_drv_twi_tx(&i2c, address, &subAddress, 1, true); 131 | 132 | while (m_xfer_done == false) {}; 133 | 134 | //comes back with error code 135 | //SEGGER_RTT_printf(0, "ReadBytes code: %d\n", err_code); 136 | //here is the problem???? 137 | //APP_ERROR_CHECK(err_code); 138 | 139 | if (err_code == NRF_SUCCESS) 140 | { 141 | m_xfer_done = false; 142 | //NRF_LOG_DEBUG("readBytes - Reading\r\n"); 143 | err_code = nrf_drv_twi_rx(&i2c, address, dest, n_bytes); 144 | //SEGGER_RTT_printf(0, "ReadBytes RX code: %d\n", err_code); 145 | //APP_ERROR_CHECK(err_code); 146 | while (m_xfer_done == false) {}; 147 | }; 148 | 149 | //NRF_LOG_DEBUG("readBytes done\r\n"); 150 | //NRF_LOG_FLUSH(); 151 | } 152 | 153 | -------------------------------------------------------------------------------- /nbproject/private/Default-build.log: -------------------------------------------------------------------------------- 1 | mkdir _build 2 | Compiling file: boards.c 3 | Compiling file: main.c 4 | ../../../main.c: In function 'main': 5 | ../../../main.c:1249:5: warning: implicit declaration of function 'SEGGER_RTT_WriteString' [-Wimplicit-function-declaration] 6 | SEGGER_RTT_WriteString(0, "\n\n***********\n"); 7 | ^~~~~~~~~~~~~~~~~~~~~~ 8 | ../../../main.c:1251:10: warning: unused variable 'erase_bonds' [-Wunused-variable] 9 | bool erase_bonds; 10 | ^~~~~~~~~~~ 11 | At top level: 12 | ../../../main.c:1162:13: warning: 'update_battery' defined but not used [-Wunused-function] 13 | static void update_battery(void) 14 | ^~~~~~~~~~~~~~ 15 | ../../../main.c:976:13: warning: 'power_manage' defined but not used [-Wunused-function] 16 | static void power_manage(void) 17 | ^~~~~~~~~~~~ 18 | ../../../main.c:952:13: warning: 'buttons_leds_init' defined but not used [-Wunused-function] 19 | static void buttons_leds_init(bool * p_erase_bonds) 20 | ^~~~~~~~~~~~~~~~~ 21 | ../../../main.c:922:13: warning: 'advertising_init' defined but not used [-Wunused-function] 22 | static void advertising_init(void) 23 | ^~~~~~~~~~~~~~~~ 24 | ../../../main.c:888:13: warning: 'peer_manager_init' defined but not used [-Wunused-function] 25 | static void peer_manager_init(void) 26 | ^~~~~~~~~~~~~~~~~ 27 | ../../../main.c:792:13: warning: 'ble_stack_init' defined but not used [-Wunused-function] 28 | static void ble_stack_init(void) 29 | ^~~~~~~~~~~~~~ 30 | ../../../main.c:593:13: warning: 'conn_params_init' defined but not used [-Wunused-function] 31 | static void conn_params_init(void) 32 | ^~~~~~~~~~~~~~~~ 33 | ../../../main.c:503:13: warning: 'ble_services_init' defined but not used [-Wunused-function] 34 | static void ble_services_init(void) 35 | ^~~~~~~~~~~~~~~~~ 36 | ../../../main.c:492:13: warning: 'gatt_init' defined but not used [-Wunused-function] 37 | static void gatt_init(void) 38 | ^~~~~~~~~ 39 | ../../../main.c:447:13: warning: 'gap_params_init' defined but not used [-Wunused-function] 40 | static void gap_params_init(void) 41 | ^~~~~~~~~~~~~~~ 42 | ../../../main.c:430:13: warning: 'RTC1_timer_stop' defined but not used [-Wunused-function] 43 | static void RTC1_timer_stop(void) 44 | ^~~~~~~~~~~~~~~ 45 | Compiling file: I2C.c 46 | ../../../I2C.c:5:0: warning: "NRF_LOG_MODULE_NAME" redefined 47 | #define NRF_LOG_MODULE_NAME "I2C" 48 | 49 | In file included from ../../../I2C.h:11:0, 50 | from ../../../I2C.c:2: 51 | ../../../../../../components/libraries/log/nrf_log.h:70:0: note: this is the location of the previous definition 52 | #define NRF_LOG_MODULE_NAME "" 53 | 54 | Compiling file: BME280.c 55 | ../../../BME280.c:6:0: warning: "NRF_LOG_MODULE_NAME" redefined 56 | #define NRF_LOG_MODULE_NAME "BME" 57 | 58 | In file included from ../../../I2C.h:11:0, 59 | from ../../../BME280.c:2: 60 | ../../../../../../components/libraries/log/nrf_log.h:70:0: note: this is the location of the previous definition 61 | #define NRF_LOG_MODULE_NAME "" 62 | 63 | Compiling file: ADC.c 64 | Compiling file: SPIFlash.c 65 | ../../../SPIFlash.c:10:0: warning: "NRF_LOG_MODULE_NAME" redefined 66 | #define NRF_LOG_MODULE_NAME "FLASH" 67 | 68 | In file included from ../../../SPIFlash.c:7:0: 69 | ../../../../../../components/libraries/log/nrf_log.h:70:0: note: this is the location of the previous definition 70 | #define NRF_LOG_MODULE_NAME "" 71 | 72 | Compiling file: nrf_log_backend_serial.c 73 | Compiling file: nrf_log_frontend.c 74 | Compiling file: app_button.c 75 | Compiling file: app_scheduler.c 76 | Compiling file: app_timer.c 77 | Compiling file: crc16.c 78 | Compiling file: fds.c 79 | Compiling file: fstorage.c 80 | Compiling file: hardfault_implementation.c 81 | Compiling file: nrf_strerror.c 82 | Compiling file: sensorsim.c 83 | Compiling file: app_error.c 84 | Compiling file: app_error_weak.c 85 | Compiling file: app_util_platform.c 86 | Compiling file: nrf_assert.c 87 | Compiling file: sdk_mapped_flags.c 88 | Compiling file: bsp.c 89 | Compiling file: bsp_btn_ble.c 90 | Compiling file: bsp_nfc.c 91 | Compiling file: nrf_queue.c 92 | Compiling file: nrf_spi_mngr.c 93 | Compiling file: nrf_drv_spi.c 94 | Compiling file: nrf_drv_clock.c 95 | Compiling file: nrf_drv_common.c 96 | Compiling file: nrf_drv_gpiote.c 97 | Compiling file: nrf_drv_twi.c 98 | Compiling file: nrf_drv_uart.c 99 | Compiling file: nrf_drv_saadc.c 100 | Compiling file: nrf_saadc.c 101 | Compiling file: nrf_drv_ppi.c 102 | Compiling file: nrf_drv_timer.c 103 | Compiling file: ble_advertising.c 104 | Compiling file: ble_advdata.c 105 | Compiling file: ble_conn_params.c 106 | Compiling file: ble_conn_state.c 107 | Compiling file: ble_srv_common.c 108 | Compiling file: gatt_cache_manager.c 109 | Compiling file: gatts_cache_manager.c 110 | Compiling file: id_manager.c 111 | Compiling file: nrf_ble_gatt.c 112 | Compiling file: peer_data_storage.c 113 | Compiling file: peer_database.c 114 | Compiling file: peer_id.c 115 | Compiling file: peer_manager.c 116 | Compiling file: pm_buffer.c 117 | Compiling file: pm_mutex.c 118 | Compiling file: security_dispatcher.c 119 | Compiling file: security_manager.c 120 | Compiling file: ble_bas.c 121 | Compiling file: ble_dis.c 122 | Compiling file: ble_hrs.c 123 | ../../../../../../components/ble/ble_services/ble_hrs/ble_hrs.c: In function 'hrm_encode_3': 124 | ../../../../../../components/ble/ble_services/ble_hrs/ble_hrs.c:229:13: warning: unused variable 'i' [-Wunused-variable] 125 | int i; 126 | ^ 127 | Compiling file: softdevice_handler.c 128 | Assembling file: gcc_startup_nrf52.S 129 | Compiling file: system_nrf52.c 130 | Compiling file: RTT_Syscalls_GCC.c 131 | Compiling file: SEGGER_RTT.c 132 | Compiling file: SEGGER_RTT_printf.c 133 | Linking target: _build/nrf52832_xxaa.out 134 | 135 | text data bss dec hex filename 136 | 51332 516 19848 71696 11810 _build/nrf52832_xxaa.out 137 | 138 | Preparing: _build/nrf52832_xxaa.hex 139 | Preparing: _build/nrf52832_xxaa.bin 140 | -------------------------------------------------------------------------------- /FDC1004.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 24 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | /* 31 | Datasheet - note that TI datasheet has key typo/error re. single/repeated measurement setup. 32 | http://www.ti.com/lit/ds/symlink/fdc1004.pdf 33 | */ 34 | 35 | #include "FDC1004.h" 36 | 37 | #define FDC1004_ADDRESS 0x50 38 | 39 | // * @brief Function for setting active 40 | void FDC1004_Turn_On(void) 41 | { 42 | 43 | uint8_t devID[2]; 44 | readBytes(FDC1004_ADDRESS, 0xFF, devID, 2); 45 | 46 | uint16_t devID_16; 47 | devID_16 = (uint16_t) devID[0] << 8 | devID[1]; 48 | 49 | SEGGER_RTT_printf(0, "FDC1004 ID:%d Should be = 4100\n", devID_16); 50 | 51 | if( devID_16 == 4100 ) FDC1004_Configure( ); 52 | 53 | } 54 | 55 | void FDC1004_Configure( void ) 56 | { 57 | uint8_t CH_config[3]; 58 | 59 | //CH_config[2] = 0x40; //= 6.4 pF 60 | //CH_config[2] = 0x20; //= 3.175 pF 61 | CH_config[2] = 0x00; //= 0 pF 62 | 63 | CH_config[0] = 0x08; //Measurement 1 Configuration 64 | CH_config[1] = 0x10; //000 100 00 65 | writeBytes( FDC1004_ADDRESS, CH_config, 3); 66 | 67 | CH_config[0] = 0x09; //Measurement 2 Configuration 68 | CH_config[1] = 0x30; //001 100 00 69 | writeBytes( FDC1004_ADDRESS, CH_config, 3); 70 | 71 | CH_config[0] = 0x0A; //Measurement 3 Configuration 72 | CH_config[1] = 0x50; //010 100 00 73 | writeBytes( FDC1004_ADDRESS, CH_config, 3); 74 | 75 | CH_config[0] = 0x0B; //Measurement 4 Configuration 76 | CH_config[1] = 0x70; //011 100 00 77 | writeBytes( FDC1004_ADDRESS, CH_config, 3); 78 | 79 | /* 80 | The FDC1004 can trigger a new measurement on the completion of the previous measurement (repeated measurements). 81 | This is setup by: 82 | 1. Setting REPEAT(Register0x0C:bit[8]) to 1. 83 | 2. Setting the corresponding MEAS_x field (Register0x0C:bit[7:4]) to 1. 84 | When the FDC1004 is setup for repeated measurements, multiple configured measurements 85 | (up to a maximum of 4) can be performed in this manner, 86 | but Register 0x0C must be written in a single transaction. 87 | */ 88 | 89 | //note the the data sheet is wrong. 0540 is repeated measurement, not single measurement! 90 | 91 | CH_config[0] = 0x0C; // FDC Register Description 92 | //CH_config[1] = 0x11; // 0 00 10 0 0 1 // 200S/s, with repeat == 0x11 93 | CH_config[1] = 0x19; // 0 00 11 0 0 1 // 400S/s, with repeat == 0x19 94 | CH_config[2] = 0xF0; // 1111 0000 = all 4 channels 95 | 96 | //let's go! 97 | writeBytes( FDC1004_ADDRESS, CH_config, 3); 98 | } 99 | 100 | float ConvertFDCToFloat( uint8_t * dM, uint8_t * dL ) 101 | { 102 | uint32_t resultR = (uint32_t)dM[0] << 16 | (uint32_t)dM[1] << 8 | dL[0]; 103 | int8_t negative = (resultR & (1 << 22)) != 0; 104 | int32_t nativeInt = 0; 105 | 106 | if (negative) 107 | nativeInt = resultR | ~((1 << 23) - 1); 108 | else 109 | nativeInt = resultR; 110 | 111 | return ((float)nativeInt / 524288.0); 112 | } 113 | 114 | void FDC1004_Get_Data( float * result ) 115 | { 116 | 117 | uint8_t dM[2]; 118 | uint8_t dL[2]; 119 | 120 | readBytes(FDC1004_ADDRESS, 0x00, dM, 2); 121 | readBytes(FDC1004_ADDRESS, 0x01, dL, 2); 122 | result[0] = ConvertFDCToFloat( dM, dL ); 123 | 124 | if( SEGGER_FDC ) 125 | { 126 | //SEGGER_RTT_printf(0, "FDC1004.1:%d %d %d\n", dM[0], dM[1], dL[0], dL[1]); 127 | SEGGER_RTT_printf(0, "FDC:%d ", (int32_t)(result[0]*1000)); 128 | } 129 | 130 | readBytes(FDC1004_ADDRESS, 0x02, dM, 2); 131 | readBytes(FDC1004_ADDRESS, 0x03, dL, 2); 132 | result[1] = ConvertFDCToFloat( dM, dL ); 133 | 134 | if( SEGGER_FDC ) 135 | { 136 | //SEGGER_RTT_printf(0, "FDC1004.2:%d %d %d\n", dM[0], dM[1], dL[0], dL[1]); 137 | SEGGER_RTT_printf(0, "%d ", (int32_t)(result[1]*1000)); 138 | } 139 | 140 | readBytes(FDC1004_ADDRESS, 0x04, dM, 2); 141 | readBytes(FDC1004_ADDRESS, 0x05, dL, 2); 142 | result[2] = ConvertFDCToFloat( dM, dL ); 143 | 144 | if( SEGGER_FDC ) 145 | { 146 | //SEGGER_RTT_printf(0, "FDC1004.3:%d %d %d\n", dM[0], dM[1], dL[0], dL[1]); 147 | SEGGER_RTT_printf(0, "%d ", (int32_t)(result[2]*1000)); 148 | } 149 | 150 | readBytes(FDC1004_ADDRESS, 0x06, dM, 2); 151 | readBytes(FDC1004_ADDRESS, 0x07, dL, 2); 152 | result[3] = ConvertFDCToFloat( dM, dL ); 153 | 154 | if( SEGGER_FDC ) 155 | { 156 | //SEGGER_RTT_printf(0, "FDC1004.4:%d %d %d\n", dM[0], dM[1], dL[0], dL[1]); 157 | SEGGER_RTT_printf(0, "%d\n", (int32_t)(result[3]*1000)); 158 | } 159 | 160 | } 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /nbproject/private/cpp_standard_headers_indexer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 | * 4 | * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. 5 | * 6 | * Oracle and Java are registered trademarks of Oracle and/or its affiliates. 7 | * Other names may be trademarks of their respective owners. 8 | * 9 | * The contents of this file are subject to the terms of either the GNU 10 | * General Public License Version 2 only ("GPL") or the Common 11 | * Development and Distribution License("CDDL") (collectively, the 12 | * "License"). You may not use this file except in compliance with the 13 | * License. You can obtain a copy of the License at 14 | * http://www.netbeans.org/cddl-gplv2.html 15 | * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the 16 | * specific language governing permissions and limitations under the 17 | * License. When distributing the software, include this License Header 18 | * Notice in each file and include the License file at 19 | * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this 20 | * particular file as subject to the "Classpath" exception as provided 21 | * by Oracle in the GPL Version 2 section of the License file that 22 | * accompanied this code. If applicable, add the following below the 23 | * License Header, with the fields enclosed by brackets [] replaced by 24 | * your own identifying information: 25 | * "Portions Copyrighted [year] [name of copyright owner]" 26 | * 27 | * If you wish your version of this file to be governed by only the CDDL 28 | * or only the GPL Version 2, indicate your decision by adding 29 | * "[Contributor] elects to include this software in this distribution 30 | * under the [CDDL or GPL Version 2] license." If you do not indicate a 31 | * single choice of license, a recipient has the option to distribute 32 | * your version of this file under either the CDDL, the GPL Version 2 or 33 | * to extend the choice of license to its licensees as provided above. 34 | * However, if you add GPL Version 2 code and therefore, elected the GPL 35 | * Version 2 license, then the option applies only if the new code is 36 | * made subject to such option by the copyright holder. 37 | * 38 | * Contributor(s): 39 | */ 40 | 41 | // List of standard headers was taken in http://en.cppreference.com/w/cpp/header 42 | 43 | #include // General purpose utilities: program control, dynamic memory allocation, random numbers, sort and search 44 | #include // Functions and macro constants for signal management 45 | #include // Macro (and function) that saves (and jumps) to an execution context 46 | #include // Handling of variable length argument lists 47 | #include // Runtime type information utilities 48 | #include // std::bitset class template 49 | #include // Function objects, designed for use with the standard algorithms 50 | #include // Various utility components 51 | #include // C-style time/date utilites 52 | #include // typedefs for types such as size_t, NULL and others 53 | #include // Low-level memory management utilities 54 | #include // Higher level memory management utilities 55 | #include // limits of integral types 56 | #include // limits of float types 57 | #include // standardized way to query properties of arithmetic types 58 | #include // Exception handling utilities 59 | #include // Standard exception objects 60 | #include // Conditionally compiled macro that compares its argument to zero 61 | #include // Macro containing the last error number 62 | #include // functions to determine the type contained in character data 63 | #include // functions for determining the type of wide character data 64 | #include // various narrow character string handling functions 65 | #include // various wide and multibyte string handling functions 66 | #include // std::basic_string class template 67 | #include // std::vector container 68 | #include // std::deque container 69 | #include // std::list container 70 | #include // std::set and std::multiset associative containers 71 | #include // std::map and std::multimap associative containers 72 | #include // std::stack container adaptor 73 | #include // std::queue and std::priority_queue container adaptors 74 | #include // Algorithms that operate on containers 75 | #include // Container iterators 76 | #include // Common mathematics functions 77 | #include // Complex number type 78 | #include // Class for representing and manipulating arrays of values 79 | #include // Numeric operations on values in containers 80 | #include // forward declarations of all classes in the input/output library 81 | #include // std::ios_base class, std::basic_ios class template and several typedefs 82 | #include // std::basic_istream class template and several typedefs 83 | #include // std::basic_ostream, std::basic_iostream class templates and several typedefs 84 | #include // several standard stream objects 85 | #include // std::basic_fstream, std::basic_ifstream, std::basic_ofstream class templates and several typedefs 86 | #include // std::basic_stringstream, std::basic_istringstream, std::basic_ostringstream class templates and several typedefs 87 | #include // std::strstream, std::istrstream, std::ostrstream(deprecated) 88 | #include // Helper functions to control the format or input and output 89 | #include // std::basic_streambuf class template 90 | #include // C-style input-output functions 91 | #include // Localization utilities 92 | #include // C localization utilities 93 | #include // empty header. The macros that appear in iso646.h in C are keywords in C++ 94 | #if __cplusplus >= 201103L 95 | #include // (since C++11) std::type_index 96 | #include // (since C++11) Compile-time type information 97 | #include // (since C++11) C++ time utilites 98 | #include // (since C++11) std::initializer_list class template 99 | #include // (since C++11) std::tuple class template 100 | #include // (since C++11) Nested allocator class 101 | #include // (since C++11) fixed-size types and limits of other types 102 | #include // (since C++11) formatting macros , intmax_t and uintmax_t math and conversions 103 | #include // (since C++11) defines std::error_code, a platform-dependent error code 104 | #include // (since C++11) C-style Unicode character conversion functions 105 | #include // (since C++11) std::array container 106 | #include // (since C++11) std::forward_list container 107 | #include // (since C++11) std::unordered_set and std::unordered_multiset unordered associative containers 108 | #include // (since C++11) std::unordered_map and std::unordered_multimap unordered associative containers 109 | #include // (since C++11) Random number generators and distributions 110 | #include // (since C++11) Compile-time rational arithmetic 111 | #include // (since C++11) Floating-point environment access functions 112 | #include // (since C++11) Unicode conversion facilities 113 | #include // (since C++11) Classes, algorithms and iterators to support regular expression processing 114 | #include // (since C++11) Atomic operations library 115 | #include // (since C++11)(deprecated in C++17) simply includes the header 116 | #include // (since C++11)(deprecated in C++17) simply includes the headers (until C++17) (since C++17) and : the overloads equivalent to the contents of the C header tgmath.h are already provided by those headers 117 | #include // (since C++11)(deprecated in C++17) defines one compatibility macro constant 118 | #include // (since C++11)(deprecated in C++17) defines one compatibility macro constant 119 | #include // (since C++11) std::thread class and supporting functions 120 | #include // (since C++11) mutual exclusion primitives 121 | #include // (since C++11) primitives for asynchronous computations 122 | #include // (since C++11) thread waiting conditions 123 | #endif 124 | #if __cplusplus >= 201300L 125 | #include // (since C++14) shared mutual exclusion primitives 126 | #endif 127 | #if __cplusplus >= 201500L 128 | #include // (since C++17) std::any class template 129 | #include // (since C++17) std::optional class template 130 | #include // (since C++17) std::variant class template 131 | #include // (since C++17) Polymorphic allocators and memory resources 132 | #include // (since C++17) std::basic_string_view class template 133 | #include // (since C++17) Predefined execution policies for parallel versions of the algorithms 134 | #include // (since C++17) std::path class and supporting functions 135 | #endif 136 | -------------------------------------------------------------------------------- /BMA280.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * The code is modified from a reference implementation by Kris Winer 8 | * (tleracorp@gmail.com) 9 | * Copyright (c) 2017, Tlera Corporation 10 | * The license terms of the TLERACORP material are: 11 | * "Library may be used freely and without limit with attribution." 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 25 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 30 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #include "BMA280.h" 37 | 38 | /* Register Map BMA280 39 | http://www.mouser.com/ds/2/783/BST-BMA280-DS000-11_published-786496.pdf 40 | */ 41 | 42 | #define BMA280_BGW_CHIPID 0x00 43 | #define BMA280_ACCD_X_LSB 0x02 44 | #define BMA280_ACCD_X_MSB 0x03 45 | #define BMA280_ACCD_Y_LSB 0x04 46 | #define BMA280_ACCD_Y_MSB 0x05 47 | #define BMA280_ACCD_Z_LSB 0x06 48 | #define BMA280_ACCD_Z_MSB 0x07 49 | #define BMA280_ACCD_TEMP 0x08 50 | #define BMA280_INT_STATUS_0 0x09 51 | #define BMA280_INT_STATUS_1 0x0A 52 | #define BMA280_INT_STATUS_2 0x0B 53 | #define BMA280_INT_STATUS_3 0x0C 54 | #define BMA280_FIFO_STATUS 0x0E 55 | #define BMA280_PMU_RANGE 0x0F 56 | #define BMA280_PMU_BW 0x10 57 | #define BMA280_PMU_LPW 0x11 58 | #define BMA280_PMU_LOW_NOISE 0x12 59 | #define BMA280_ACCD_HBW 0x13 60 | #define BMA280_BGW_SOFTRESET 0x14 61 | #define BMA280_INT_EN_0 0x16 62 | #define BMA280_INT_EN_1 0x17 63 | #define BMA280_INT_EN_2 0x18 64 | #define BMA280_INT_MAP_0 0x19 65 | #define BMA280_INT_MAP_1 0x1A 66 | #define BMA280_INT_MAP_2 0x1B 67 | #define BMA280_INT_SRC 0x1E 68 | #define BMA280_INT_OUT_CTRL 0x20 69 | #define BMA280_INT_RST_LATCH 0x21 70 | #define BMA280_INT_0 0x22 71 | #define BMA280_INT_1 0x23 72 | #define BMA280_INT_2 0x24 73 | #define BMA280_INT_3 0x25 74 | #define BMA280_INT_4 0x26 75 | #define BMA280_INT_5 0x27 76 | #define BMA280_INT_6 0x28 77 | #define BMA280_INT_7 0x29 78 | #define BMA280_INT_8 0x2A 79 | #define BMA280_INT_9 0x2B 80 | #define BMA280_INT_A 0x2C 81 | #define BMA280_INT_B 0x2D 82 | #define BMA280_INT_C 0x2E 83 | #define BMA280_INT_D 0x2F 84 | #define BMA280_FIFO_CONFIG_0 0x30 85 | #define BMA280_PMU_SELF_TEST 0x32 86 | #define BMA280_TRIM_NVM_CTRL 0x33 87 | #define BMA280_BGW_SPI3_WDT 0x34 88 | #define BMA280_OFC_CTRL 0x36 89 | #define BMA280_OFC_SETTING 0x37 90 | #define BMA280_OFC_OFFSET_X 0x38 91 | #define BMA280_OFC_OFFSET_Y 0x39 92 | #define BMA280_OFC_OFFSET_Z 0x3A 93 | #define BMA280_TRIM_GP0 0x3B 94 | #define BMA280_TRIM_GP1 0x3C 95 | #define BMA280_FIFO_CONFIG_1 0x3E 96 | #define BMA280_FIFO_DATA 0x3F 97 | 98 | #define BMA280_ADDRESS 0x18 // if ADO is 0 (default) 99 | 100 | #define AFS_2G 0x02 101 | #define AFS_4G 0x05 102 | #define AFS_8G 0x08 103 | #define AFS_16G 0x0C 104 | 105 | #define BW_7_81Hz 0x08 // 15.62 Hz sample rate, etc 106 | #define BW_15_63Hz 0x09 107 | #define BW_31_25Hz 0x0A 108 | #define BW_62_5Hz 0x0B 109 | #define BW_125Hz 0x0C // 250 Hz sample rate 110 | #define BW_250Hz 0x0D 111 | #define BW_500Hz 0x0E 112 | #define BW_1000Hz 0x0F // 2 kHz sample rate == unfiltered data 113 | 114 | #define normal_Mode 0x00 //define power modes 115 | #define deepSuspend_Mode 0x01 116 | #define lowPower_Mode 0x02 117 | #define suspend_Mode 0x04 118 | 119 | #define sleep_0_5ms 0x05 // define sleep duration in low power modes 120 | #define sleep_1ms 0x06 121 | #define sleep_2ms 0x07 122 | #define sleep_4ms 0x08 123 | #define sleep_6ms 0x09 124 | #define sleep_10ms 0x0A 125 | #define sleep_25ms 0x0B 126 | #define sleep_50ms 0x0C 127 | #define sleep_100ms 0x0D 128 | #define sleep_500ms 0x0E 129 | #define sleep_1000ms 0x0F 130 | 131 | uint8_t BMA_intPin1; 132 | uint8_t BMA_intPin2; 133 | float BMA_aRes; 134 | 135 | // * @brief Function for setting active 136 | void BMA280_Turn_On_Fast( void ) 137 | { 138 | uint8_t c = readByte(BMA280_ADDRESS, BMA280_BGW_CHIPID); 139 | SEGGER_RTT_printf(0, "BMA280 ID:%d Should be = 251\n", c); 140 | 141 | uint8_t Ascale = AFS_2G; 142 | uint8_t BW = BW_500Hz; 143 | uint8_t power_Mode = normal_Mode; 144 | uint8_t sleep_dur = sleep_500ms; 145 | 146 | // set full-scale range 147 | writeByte(BMA280_ADDRESS, BMA280_PMU_RANGE, Ascale); 148 | // set bandwidth (and thereby sample rate) 149 | writeByte(BMA280_ADDRESS, BMA280_PMU_BW, BW); 150 | // set power mode and sleep duration 151 | writeByte(BMA280_ADDRESS, BMA280_PMU_LPW, power_Mode << 5 | sleep_dur << 1); 152 | 153 | } 154 | 155 | void BMA280_Turn_On_Slow( void ) 156 | { 157 | uint8_t BW = BW_7_81Hz; 158 | uint8_t power_Mode = lowPower_Mode; 159 | uint8_t sleep_dur = sleep_500ms; 160 | 161 | // set bandwidth (and thereby sample rate) 162 | writeByte(BMA280_ADDRESS, BMA280_PMU_BW, BW); 163 | // set power mode and sleep duration 164 | writeByte(BMA280_ADDRESS, BMA280_PMU_LPW, power_Mode << 5 | sleep_dur << 1); 165 | 166 | } 167 | 168 | void BMA280_Turn_Off( void ) 169 | { 170 | /* 171 | uint8_t packet[3]; 172 | packet[0] = (uint8_t)VEML6040_CONF; 173 | packet[1] = (uint8_t)(IT_1280 << 4 | 0x01); // Bit 3 must be 0, bit 0 is 0 for run and 1 for shutdown, LS Byte 174 | packet[2] = (uint8_t)0x00; 175 | writeBytes(VEML6040_ADDRESS, packet, 3); 176 | */ 177 | } 178 | 179 | void BMA280_Get_Data(int16_t * dest) 180 | { 181 | uint8_t rawData[6]; // x/y/z accel register data stored here 182 | readBytes(BMA280_ADDRESS, BMA280_ACCD_X_LSB, rawData, 6); // Read the 6 raw data registers into data array 183 | dest[0] = ((int16_t)rawData[1] << 8) | rawData[0]; // Turn the MSB and LSB into a signed 14-bit value 184 | dest[1] = ((int16_t)rawData[3] << 8) | rawData[2]; 185 | dest[2] = ((int16_t)rawData[5] << 8) | rawData[4]; 186 | if (SEGGER_BMA ) 187 | SEGGER_RTT_printf(0, "BMA280:%d %d %d\n", dest[0], dest[1], dest[2]); 188 | } 189 | 190 | void BMA280_Calibrate( void ) 191 | { 192 | //must be in normal power mode, and set to +/- 2g 193 | SEGGER_RTT_printf(0, "Hold flat and motionless for bias calibration\n"); 194 | 195 | nrf_delay_ms(3000); 196 | 197 | uint8_t rawData[2]; // x/y/z accel register data stored here 198 | float FCres = 7.8125f; // fast compensation offset mg/LSB 199 | 200 | writeByte(BMA280_ADDRESS, BMA280_OFC_SETTING, 0x20 | 0x01); // set target data to 0g, 0g, and +1g, cutoff at 1% of bandwidth 201 | 202 | writeByte(BMA280_ADDRESS, BMA280_OFC_CTRL, 0x20); // x-axis calibration 203 | while(!(0x10 & readByte(BMA280_ADDRESS, BMA280_OFC_CTRL))) { }; // wait for calibration completion 204 | 205 | writeByte(BMA280_ADDRESS, BMA280_OFC_CTRL, 0x40); // y-axis calibration 206 | while(!(0x10 & readByte(BMA280_ADDRESS, BMA280_OFC_CTRL))) { }; // wait for calibration completion 207 | 208 | writeByte(BMA280_ADDRESS, BMA280_OFC_CTRL, 0x60); // z-axis calibration 209 | while(!(0x10 & readByte(BMA280_ADDRESS, BMA280_OFC_CTRL))) { }; // wait for calibration completion 210 | 211 | readBytes(BMA280_ADDRESS, BMA280_OFC_OFFSET_X, &rawData[0], 2); 212 | int16_t offsetX = ((int16_t)rawData[1] << 8) | 0x00; 213 | 214 | readBytes(BMA280_ADDRESS, BMA280_OFC_OFFSET_Y, &rawData[0], 2); 215 | int16_t offsetY = ((int16_t)rawData[1] << 8) | 0x00; 216 | 217 | readBytes(BMA280_ADDRESS, BMA280_OFC_OFFSET_Z, &rawData[0], 2); 218 | int16_t offsetZ = ((int16_t)rawData[1] << 8) | 0x00; 219 | 220 | SEGGER_RTT_printf(0, "Bias calibration completed\n"); 221 | SEGGER_RTT_printf(0, "x-axis offset = %d mg\n", (int16_t)(100.0f*(float)offsetX*FCres/256.0f)); 222 | SEGGER_RTT_printf(0, "y-axis offset = %d mg\n", (int16_t)(100.0f*(float)offsetY*FCres/256.0f)); 223 | SEGGER_RTT_printf(0, "z-axis offset = %d mg\n", (int16_t)(100.0f*(float)offsetZ*FCres/256.0f)); 224 | 225 | } 226 | 227 | -------------------------------------------------------------------------------- /ble_ma.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 24 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * Parts of this software, primarily the basic BLE control code, were derived or 30 | * directly copied from the Nordic reference implementations available in their SDK. 31 | * For those sections, the following license applies: 32 | * 33 | * Copyright (c) 2010 - 2017, Nordic Semiconductor ASA 34 | * All rights reserved. 35 | * 36 | * Redistribution and use in source and binary forms, with or without modification, 37 | * are permitted provided that the following conditions are met: 38 | * 39 | * 1. Redistributions of source code must retain the above copyright notice, this 40 | * list of conditions and the following disclaimer. 41 | * 42 | * 2. Redistributions in binary form, except as embedded into a Nordic 43 | * Semiconductor ASA integrated circuit in a product or a software update for 44 | * such product, must reproduce the above copyright notice, this list of 45 | * conditions and the following disclaimer in the documentation and/or other 46 | * materials provided with the distribution. 47 | * 48 | * 3. Neither the name of Nordic Semiconductor ASA nor the names of its 49 | * contributors may be used to endorse or promote products derived from this 50 | * software without specific prior written permission. 51 | * 52 | * 4. This software, with or without modification, must only be used with a 53 | * Nordic Semiconductor ASA integrated circuit. 54 | * 55 | * 5. Any software provided in binary form under this license must not be reverse 56 | * engineered, decompiled, modified and/or disassembled. 57 | * 58 | * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS 59 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 60 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 61 | * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE 62 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 63 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 64 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 67 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 68 | */ 69 | 70 | #ifndef BLE_MA_H__ 71 | #define BLE_MA_H__ 72 | 73 | #include 74 | #include 75 | #include "ble.h" 76 | #include "ble_srv_common.h" 77 | #include "nrf_ble_gatt.h" 78 | 79 | #ifdef __cplusplus 80 | extern "C" { 81 | #endif 82 | 83 | /**@brief Mentaid Service event type. */ 84 | typedef enum 85 | { 86 | BLE_MA_EVT_NOTIFICATION_ENABLED, /**< Mentaid value notification enabled event. */ 87 | BLE_MA_EVT_NOTIFICATION_DISABLED /**< Mentaid value notification disabled event. */ 88 | } ble_ma_evt_type_t; 89 | 90 | /**@brief Mentaid Service event. */ 91 | typedef struct 92 | { 93 | ble_ma_evt_type_t evt_type; /**< Type of event. */ 94 | } ble_ma_evt_t; 95 | 96 | // Forward declaration of the ble_ma_t type. 97 | typedef struct ble_ma_s ble_ma_t; 98 | 99 | /**@brief Mentaid Service event handler type. */ 100 | typedef void (*ble_ma_evt_handler_t) (ble_ma_t * p_ma, ble_ma_evt_t * p_evt); 101 | 102 | /**@brief Mentaid Service init structure. This contains all options and data needed for 103 | * initialization of the service. */ 104 | typedef struct 105 | { 106 | ble_ma_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Mentaid Service. */ 107 | uint8_t * p_board_state; /**< If not NULL, initial value of the firmware state characteristic. */ 108 | ble_srv_cccd_security_mode_t ma_attr_md; /**< Initial security level for service measurement attribute */ 109 | ble_srv_security_mode_t command_attr_md; /**< Initial security level for the command attribute */ 110 | ble_srv_cccd_security_mode_t status_attr_md; /**< Initial security level for the status attribute */ 111 | uint8_t current_status; /**< Current status of the board */ 112 | uint8_t current_statusN; /**< Current status of the board */ 113 | } ble_ma_init_t; 114 | 115 | /**@brief Mentaid Service structure. This contains various status information for the service. */ 116 | struct ble_ma_s 117 | { 118 | ble_ma_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Mentaid Service. */ 119 | uint16_t service_handle; /**< Handle of Mentaid Service (as provided by the BLE stack). */ 120 | uint8_t current_status; /**< Current status of the board */ 121 | ble_gatts_char_handles_t ma_handles; /**< Handles related to the Mentaid Measurement characteristic. */ 122 | ble_gatts_char_handles_t command_handles; /**< Handles related to the Mentaid Command characteristic. */ 123 | ble_gatts_char_handles_t status_handles; /**< Handles related to the Mentaid Status characteristic. */ 124 | uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */ 125 | uint8_t max_ma_len; /**< Current maximum MA measurement length, adjusted according to the current ATT MTU. */ 126 | }; 127 | 128 | //static uint32_t mentaid_measurement_char_add(ble_ma_t * p_ma, const ble_ma_init_t * p_ma_init); 129 | 130 | //static uint32_t mentaid_command_char_add(ble_ma_t * p_ma, const ble_ma_init_t * p_ma_init); 131 | 132 | //static uint32_t mentaid_status_char_add(ble_ma_t * p_ma, const ble_ma_init_t * p_ma_init); 133 | 134 | /**@brief Function for initializing the Mentaid Service. 135 | * 136 | * @param[out] p_hrs Mentaid structure. This structure will have to be supplied by 137 | * the application. It will be initialized by this function, and will later 138 | * be used to identify this particular service instance. 139 | * @param[in] p_ma_init Information needed to initialize the service. 140 | * 141 | * @return NRF_SUCCESS on successful initialization of service, otherwise an error code. 142 | */ 143 | uint32_t ble_ma_init(ble_ma_t * p_ma, const ble_ma_init_t * p_ma_init); 144 | 145 | 146 | /**@brief Function for handling the GATT module's events. 147 | * 148 | * @details Handles all events from the GATT module of interest to the Mentaid Service. 149 | * 150 | * @param[in] p_hrs Mentaid Service structure. 151 | * @param[in] p_gatt_evt Event received from the GATT module. 152 | */ 153 | void ble_ma_on_gatt_evt(ble_ma_t * p_ma, const nrf_ble_gatt_evt_t * p_gatt_evt); 154 | 155 | 156 | /**@brief Function for handling the Application's BLE Stack events. 157 | * 158 | * @details Handles all events from the BLE stack of interest to the Mentaid Service. 159 | * 160 | * @param[in] p_hrs Mentaid Service structure. 161 | * @param[in] p_ble_evt Event received from the BLE stack. 162 | */ 163 | void ble_ma_on_ble_evt(ble_ma_t * p_hrs, ble_evt_t * p_ble_evt); 164 | 165 | /**@brief Function for sending heart rate measurement if notification has been enabled. 166 | */ 167 | 168 | uint8_t ma_encode( ble_ma_t * p_ma, uint16_t hr, uint8_t b8, uint8_t p1, uint8_t t1, uint8_t h1, 169 | uint16_t l_white, int16_t ax, int16_t ay, int16_t az, uint16_t storage, uint8_t * p_encoded_buffer); 170 | 171 | uint32_t ma_measurement_send(ble_ma_t * p_ma, uint16_t hr, uint8_t b8, uint8_t p1, uint8_t t1, uint8_t h1, 172 | uint16_t l_white, int16_t ax, int16_t ay, int16_t az, uint16_t storage); 173 | 174 | uint32_t ma_measurement_send_16(ble_ma_t * p_ma, uint8_t * data ); 175 | 176 | uint32_t ma_status_send( ble_ma_t * p_ma, uint8_t status ); 177 | 178 | 179 | #ifdef __cplusplus 180 | } 181 | #endif 182 | 183 | #endif // BLE_MA_H__ 184 | 185 | /** @} */ 186 | -------------------------------------------------------------------------------- /BME280.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * The code is modified from a reference implementation by Kris Winer 8 | * (tleracorp@gmail.com) 9 | * Copyright (c) 2017, Tlera Corporation 10 | * The license terms of the TLERACORP material are: 11 | * "Library may be used freely and without limit with attribution." 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 25 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 30 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #include "BME280.h" 37 | 38 | #define BME280_ADDRESS_1 0x76 39 | 40 | #define BME280_ID 0xD0 41 | 42 | #define BME280_PRESS_MSB 0xF7 43 | #define BME280_PRESS_LSB 0xF8 44 | #define BME280_PRESS_XLSB 0xF9 45 | 46 | #define BME280_TEMP_MSB 0xFA 47 | #define BME280_TEMP_LSB 0xFB 48 | #define BME280_TEMP_XLSB 0xFC 49 | 50 | #define BME280_HUM_MSB 0xFD 51 | #define BME280_HUM_LSB 0xFE 52 | 53 | #define BME280_CONFIG 0xF5 54 | #define BME280_CTRL_MEAS 0xF4 55 | #define BME280_STATUS 0xF3 56 | #define BME280_CTRL_HUM 0xF2 57 | #define BME280_RESET 0xE0 58 | #define BME280_CALIB00 0x88 59 | #define BME280_CALIB26 0xE1 60 | 61 | enum Posr {P_OSR_00 = 0, /* no op */ P_OSR_01, P_OSR_02, P_OSR_04, P_OSR_08, P_OSR_16}; 62 | enum Hosr {H_OSR_00 = 0, /* no op */ H_OSR_01, H_OSR_02, H_OSR_04, H_OSR_08, H_OSR_16}; 63 | enum Tosr {T_OSR_00 = 0, /* no op */ T_OSR_01, T_OSR_02, T_OSR_04, T_OSR_08, T_OSR_16}; 64 | enum IIRFilter {full = 0, /* bandwidth at full sample rate */ BW0_223ODR, BW0_092ODR, BW0_042ODR, BW0_021ODR /* bandwidth at 0.021 x sample rate */ }; 65 | enum Mode {BME280Sleep = 0, forced, forced2, normal}; 66 | enum SBy {t_00_5ms = 0, t_62_5ms, t_125ms, t_250ms, t_500ms, t_1000ms, t_10ms, t_20ms}; 67 | 68 | // Read and store calibration data 69 | uint8_t calib26[26]; 70 | uint8_t calib7[7]; 71 | 72 | //from read PTH 73 | static uint8_t rawData[8]; // 20-bit pressure register data stored here 74 | 75 | int32_t result[3]; 76 | int32_t var1, var2, t_fine, adc_T; 77 | 78 | //from Pressure comp 79 | int32_t varP1, varP2; 80 | uint32_t P; 81 | 82 | // BME280 compensation parameters 83 | uint8_t dig_H1, dig_H3, dig_H6; 84 | uint16_t dig_T1, dig_P1, dig_H4, dig_H5; 85 | int16_t dig_T2, dig_T3, dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9, dig_H2; 86 | 87 | //uint32_t delt_t = 0, count = 0, sumCount = 0, slpcnt = 0; // used to control display output rate 88 | 89 | // Specify BME280 configuration 90 | // set pressure and temperature output data rate 91 | uint8_t Posr = P_OSR_16, Hosr = H_OSR_16, Tosr = T_OSR_02, Mode = normal, IIRFilter = BW0_021ODR, SBy = t_62_5ms; 92 | 93 | // * @brief Function for setting active 94 | void BME280_Turn_On(void) 95 | { 96 | uint8_t e = readByte(BME280_ADDRESS_1, BME280_ID); 97 | 98 | SEGGER_RTT_printf(0, "BME280 ID:%d Should be = 96\n", e); 99 | 100 | if(e == 0x60) { 101 | writeByte( BME280_ADDRESS_1, BME280_RESET, 0xB6 ); // reset BME280 before initialization 102 | nrf_delay_ms(100); 103 | BME280_Configure( BME280_ADDRESS_1 ); // Initialize BME280 altimeter 104 | nrf_delay_ms(100); 105 | }; 106 | 107 | } 108 | 109 | void BME280_Configure( uint8_t address ) 110 | { 111 | // Configure the BME280 112 | 113 | // Set H oversampling rate 114 | writeByte(address, BME280_CTRL_HUM, 0x07 & Hosr); 115 | 116 | // Set T and P oversampling rates and sensor mode 117 | writeByte(address, BME280_CTRL_MEAS, Tosr << 5 | Posr << 2 | Mode); 118 | 119 | // Set standby time interval in normal mode and bandwidth 120 | writeByte(address, BME280_CONFIG, SBy << 5 | IIRFilter << 2); 121 | 122 | readBytes(address, BME280_CALIB00, calib26, 26); 123 | 124 | dig_T1 = (uint16_t)(((uint16_t) calib26[ 1] << 8) | calib26[ 0]); 125 | //NRF_LOG_DEBUG("BME280T1:%d\r\n",dig_T1); 126 | dig_T2 = ( int16_t)((( int16_t) calib26[ 3] << 8) | calib26[ 2]); 127 | //NRF_LOG_DEBUG("BME280T2:%d\r\n",dig_T2); 128 | dig_T3 = ( int16_t)((( int16_t) calib26[ 5] << 8) | calib26[ 4]); 129 | //NRF_LOG_DEBUG("BME280T3:%d\r\n",dig_T3); 130 | dig_P1 = (uint16_t)(((uint16_t) calib26[ 7] << 8) | calib26[ 6]); 131 | //NRF_LOG_DEBUG("BME280P1:%d\r\n",dig_P1); 132 | dig_P2 = ( int16_t)((( int16_t) calib26[ 9] << 8) | calib26[ 8]); 133 | dig_P3 = ( int16_t)((( int16_t) calib26[11] << 8) | calib26[10]); 134 | dig_P4 = ( int16_t)((( int16_t) calib26[13] << 8) | calib26[12]); 135 | dig_P5 = ( int16_t)((( int16_t) calib26[15] << 8) | calib26[14]); 136 | dig_P6 = ( int16_t)((( int16_t) calib26[17] << 8) | calib26[16]); 137 | dig_P7 = ( int16_t)((( int16_t) calib26[19] << 8) | calib26[18]); 138 | dig_P8 = ( int16_t)((( int16_t) calib26[21] << 8) | calib26[20]); 139 | dig_P9 = ( int16_t)((( int16_t) calib26[23] << 8) | calib26[22]); 140 | 141 | //24 is missing - this is not typo - complain to Bosch 142 | dig_H1 = calib26[25]; 143 | 144 | readBytes(address, BME280_CALIB26, calib7, 7); 145 | 146 | dig_H2 = ( int16_t)((( int16_t) calib7[1] << 8) | calib7[0]); 147 | dig_H3 = calib7[2]; 148 | dig_H4 = ( int16_t)(((( int16_t) calib7[3] << 8) | (0x0F & calib7[4]) << 4) >> 4); 149 | dig_H5 = ( int16_t)(((( int16_t) calib7[5] << 8) | (0xF0 & calib7[4]) ) >> 4 ); 150 | dig_H6 = calib7[6]; 151 | 152 | } 153 | 154 | void BME280_Get_Data(int32_t * resultPTH) 155 | { 156 | readBytes(BME280_ADDRESS_1, BME280_PRESS_MSB, rawData, 8); 157 | 158 | //Pressure 159 | result[0] = (uint32_t) (((uint32_t) rawData[0] << 16 | (uint32_t) rawData[1] << 8 | rawData[2]) >> 4); 160 | result[1] = (uint32_t) (((uint32_t) rawData[3] << 16 | (uint32_t) rawData[4] << 8 | rawData[5]) >> 4); 161 | result[2] = (uint16_t) (((uint16_t) rawData[6] << 8 | rawData[7]) ); 162 | 163 | //Need t_fine for all three compensations 164 | adc_T = result[1]; 165 | 166 | var1 = (((( adc_T >> 3) - ((int32_t)dig_T1 << 1))) * ((int32_t)dig_T2)) >> 11; 167 | var2 = (((((adc_T >> 4) - ((int32_t)dig_T1)) * ((adc_T >> 4) - ((int32_t)dig_T1))) >> 12) * ((int32_t)dig_T3)) >> 14; 168 | 169 | t_fine = var1 + var2; 170 | 171 | resultPTH[0] = BME280_Compensate_P(result[0], t_fine); 172 | resultPTH[1] = BME280_Compensate_T( t_fine); 173 | resultPTH[2] = BME280_Compensate_H(result[2], t_fine); 174 | 175 | //SEGGER_RTT_printf(0, "BME280:%d\n", result[2]); 176 | 177 | if ( SEGGER_BME ) 178 | SEGGER_RTT_printf(0, "BME280:%d %d %d\n", resultPTH[0], resultPTH[1], resultPTH[2]); 179 | 180 | } 181 | 182 | // Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22integer and 10fractional bits). 183 | // Output value of “47445”represents 47445/1024= 46.333%RH 184 | uint32_t BME280_Compensate_H(int32_t adc_H, int32_t t_fine) 185 | { 186 | int32_t varH; 187 | varH = (t_fine - ((int32_t)76800)); 188 | varH = (((((adc_H << 14) - (((int32_t)dig_H4) << 20) - (((int32_t)dig_H5) * varH)) + 189 | ((int32_t)16384)) >> 15) * (((((((varH * ((int32_t)dig_H6)) >> 10) * (((varH * 190 | ((int32_t)dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) * ((int32_t)dig_H2) + 8192) >> 14)); 191 | varH = (varH - (((((varH >> 15) * (varH >> 15)) >> 7) * ((int32_t)dig_H1)) >> 4)); 192 | varH = (varH < 0 ? 0 : varH); 193 | varH = (varH > 419430400 ? 419430400 : varH); 194 | return(uint32_t)(varH >> 12); 195 | } 196 | 197 | // Returns temperature in DegC, resolution is 0.01 DegC. Output value of 198 | // “5123” equals 51.23 DegC. 199 | int32_t BME280_Compensate_T(int32_t t_fine) 200 | { 201 | int32_t T; 202 | //var1 = ((((adc_T >> 3) - ((int32_t)dig_T1 << 1))) * ((int32_t)dig_T2)) >> 11; 203 | //var2 = (((((adc_T >> 4) - ((int32_t)dig_T1)) * ((adc_T >> 4) - ((int32_t)dig_T1))) >> 12) * ((int32_t)dig_T3)) >> 14; 204 | //t_fine = var1 + var2; 205 | T = (t_fine * 5 + 128) >> 8; 206 | return T; 207 | } 208 | 209 | // Returns pressure in Pa as unsigned 32 bit integer. Output value of “96386” equals 96386 Pa = 963.86 hPa 210 | uint32_t BME280_Compensate_P(int32_t adc_P, int32_t t_fine) 211 | { 212 | varP1 = (t_fine>>1) - (int32_t)64000; 213 | varP2 = (((varP1>>2) * (varP1>>2)) >> 11 ) * ((int32_t)dig_P6); 214 | varP2 = varP2 + ((varP1*((int32_t)dig_P5))<<1); 215 | varP2 = (varP2>>2)+(((int32_t)dig_P4)<<16); 216 | varP1 = (((dig_P3 * (((varP1>>2) * (varP1>>2)) >> 13 )) >> 3) + ((((int32_t)dig_P2) * varP1)>>1))>>18; 217 | varP1 = ((((32768+varP1))*((int32_t)dig_P1))>>15); 218 | if (varP1 == 0) 219 | { 220 | return 0; // avoid exception caused by division by zero 221 | } 222 | P = (((uint32_t)(((int32_t)1048576)-adc_P)-(varP2>>12)))*3125; 223 | if (P < 0x80000000) 224 | { 225 | P = (P << 1) / ((uint32_t)varP1); 226 | } 227 | else 228 | { 229 | P = (P / (uint32_t)varP1) * 2; 230 | } 231 | varP1 = (((int32_t)dig_P9) * ((int32_t)(((P>>3) * (P>>3))>>13)))>>12; 232 | varP2 = (((int32_t)(P>>2)) * ((int32_t)dig_P8))>>13; 233 | P = (uint32_t)((int32_t)P + ((varP1 + varP2 + dig_P7) >> 4)); 234 | return P; 235 | } 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /pca10040/s132/armgcc/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := mentaid 2 | TARGETS := nrf52832_xxaa 3 | OUTPUT_DIRECTORY := _build 4 | 5 | #SDK_ROOT := ../../../../../.. 6 | #PROJ_DIR := ../../.. 7 | 8 | #/Users/janliphardt/GH_wearable_Firmware/ 9 | #/ARM/nRF5_SDK_13/ 10 | 11 | PROJ_DIR := /Users/janliphardt/Documents/GitHub/wearable_nRF52_Firmware 12 | SDK_ROOT := /Users/janliphardt/opt/nRF5_SDK_13 13 | NRF_ROOT := /Users/janliphardt/opt/nRF5_Command/nrfjprog 14 | 15 | $(OUTPUT_DIRECTORY)/nrf52832_xxaa.out: LINKER_SCRIPT := mentaid.ld 16 | # 17 | # Source files common to all targets 18 | SRC_FILES += \ 19 | $(SDK_ROOT)/components/boards/boards.c \ 20 | $(PROJ_DIR)/main.c \ 21 | $(PROJ_DIR)/I2C.c \ 22 | $(PROJ_DIR)/BME280.c \ 23 | $(PROJ_DIR)/ADC.c \ 24 | $(PROJ_DIR)/SPIFlash.c \ 25 | $(PROJ_DIR)/VEML6040.c \ 26 | $(PROJ_DIR)/BMA280.c \ 27 | $(PROJ_DIR)/FDC1004.c \ 28 | $(PROJ_DIR)/AD5593R.c \ 29 | $(PROJ_DIR)/app_pwm.c \ 30 | $(PROJ_DIR)/ble_ma.c \ 31 | $(PROJ_DIR)/ics43434.c \ 32 | $(SDK_ROOT)/components/libraries/log/src/nrf_log_backend_serial.c \ 33 | $(SDK_ROOT)/components/libraries/log/src/nrf_log_frontend.c \ 34 | $(SDK_ROOT)/components/libraries/button/app_button.c \ 35 | $(SDK_ROOT)/components/libraries/scheduler/app_scheduler.c \ 36 | $(SDK_ROOT)/components/libraries/timer/app_timer.c \ 37 | $(SDK_ROOT)/components/libraries/crc16/crc16.c \ 38 | $(SDK_ROOT)/components/libraries/fds/fds.c \ 39 | $(SDK_ROOT)/components/libraries/fstorage/fstorage.c \ 40 | $(SDK_ROOT)/components/libraries/hardfault/hardfault_implementation.c \ 41 | $(SDK_ROOT)/components/libraries/strerror/nrf_strerror.c \ 42 | $(SDK_ROOT)/components/libraries/sensorsim/sensorsim.c \ 43 | $(SDK_ROOT)/components/libraries/util/app_error.c \ 44 | $(SDK_ROOT)/components/libraries/util/app_error_weak.c \ 45 | $(SDK_ROOT)/components/libraries/util/app_util_platform.c \ 46 | $(SDK_ROOT)/components/libraries/util/nrf_assert.c \ 47 | $(SDK_ROOT)/components/libraries/util/sdk_mapped_flags.c \ 48 | $(SDK_ROOT)/components/libraries/bsp/bsp.c \ 49 | $(SDK_ROOT)/components/libraries/bsp/bsp_btn_ble.c \ 50 | $(SDK_ROOT)/components/libraries/bsp/bsp_nfc.c \ 51 | $(SDK_ROOT)/components/libraries/queue/nrf_queue.c \ 52 | $(SDK_ROOT)/components/libraries/spi_mngr/nrf_spi_mngr.c \ 53 | $(SDK_ROOT)/components/drivers_nrf/spi_master/nrf_drv_spi.c \ 54 | $(SDK_ROOT)/components/drivers_nrf/clock/nrf_drv_clock.c \ 55 | $(SDK_ROOT)/components/drivers_nrf/common/nrf_drv_common.c \ 56 | $(SDK_ROOT)/components/drivers_nrf/gpiote/nrf_drv_gpiote.c \ 57 | $(SDK_ROOT)/components/drivers_nrf/twi_master/nrf_drv_twi.c \ 58 | $(SDK_ROOT)/components/drivers_nrf/uart/nrf_drv_uart.c \ 59 | $(SDK_ROOT)/components/drivers_nrf/saadc/nrf_drv_saadc.c \ 60 | $(SDK_ROOT)/components/drivers_nrf/hal/nrf_saadc.c \ 61 | $(SDK_ROOT)/components/drivers_nrf/ppi/nrf_drv_ppi.c \ 62 | $(SDK_ROOT)/components/drivers_nrf/timer/nrf_drv_timer.c \ 63 | $(SDK_ROOT)/components/drivers_nrf/i2s/nrf_drv_i2s.c \ 64 | $(SDK_ROOT)/components/ble/ble_advertising/ble_advertising.c \ 65 | $(SDK_ROOT)/components/ble/common/ble_advdata.c \ 66 | $(SDK_ROOT)/components/ble/common/ble_conn_params.c \ 67 | $(SDK_ROOT)/components/ble/common/ble_conn_state.c \ 68 | $(SDK_ROOT)/components/ble/common/ble_srv_common.c \ 69 | $(SDK_ROOT)/components/ble/peer_manager/gatt_cache_manager.c \ 70 | $(SDK_ROOT)/components/ble/peer_manager/gatts_cache_manager.c \ 71 | $(SDK_ROOT)/components/ble/peer_manager/id_manager.c \ 72 | $(SDK_ROOT)/components/ble/nrf_ble_gatt/nrf_ble_gatt.c \ 73 | $(SDK_ROOT)/components/ble/peer_manager/peer_data_storage.c \ 74 | $(SDK_ROOT)/components/ble/peer_manager/peer_database.c \ 75 | $(SDK_ROOT)/components/ble/peer_manager/peer_id.c \ 76 | $(SDK_ROOT)/components/ble/peer_manager/peer_manager.c \ 77 | $(SDK_ROOT)/components/ble/peer_manager/pm_buffer.c \ 78 | $(SDK_ROOT)/components/ble/peer_manager/pm_mutex.c \ 79 | $(SDK_ROOT)/components/ble/peer_manager/security_dispatcher.c \ 80 | $(SDK_ROOT)/components/ble/peer_manager/security_manager.c \ 81 | $(SDK_ROOT)/components/ble/ble_services/ble_bas/ble_bas.c \ 82 | $(SDK_ROOT)/components/ble/ble_services/ble_dis/ble_dis.c \ 83 | $(SDK_ROOT)/components/ble/ble_services/ble_hrs/ble_hrs.c \ 84 | $(SDK_ROOT)/components/softdevice/common/softdevice_handler/softdevice_handler.c \ 85 | $(SDK_ROOT)/components/toolchain/gcc/gcc_startup_nrf52.S \ 86 | $(SDK_ROOT)/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.c \ 87 | $(SDK_ROOT)/components/drivers_nrf/nrf_soc_nosd/nrf_soc.c \ 88 | $(SDK_ROOT)/components/toolchain/system_nrf52.c \ 89 | $(SDK_ROOT)/external/segger_rtt/RTT_Syscalls_GCC.c \ 90 | $(SDK_ROOT)/external/segger_rtt/SEGGER_RTT.c \ 91 | $(SDK_ROOT)/external/segger_rtt/SEGGER_RTT_printf.c \ 92 | 93 | # Include folders common to all targets 94 | INC_FOLDERS += \ 95 | $(PROJ_DIR) \ 96 | $(SDK_ROOT)/components/device \ 97 | $(SDK_ROOT)/components/drivers_nrf/comp \ 98 | $(SDK_ROOT)/components/drivers_nrf/twi_master \ 99 | $(SDK_ROOT)/components/drivers_nrf/gpiote \ 100 | $(SDK_ROOT)/components/drivers_nrf/common \ 101 | $(SDK_ROOT)/components/drivers_nrf/i2s \ 102 | $(SDK_ROOT)/components/drivers_nrf/uart \ 103 | $(SDK_ROOT)/components/drivers_nrf/wdt \ 104 | $(SDK_ROOT)/components/drivers_nrf/saadc \ 105 | $(SDK_ROOT)/components/drivers_nrf/hal \ 106 | $(SDK_ROOT)/components/drivers_nrf/ppi \ 107 | $(SDK_ROOT)/components/drivers_nrf/timer \ 108 | $(SDK_ROOT)/components/drivers_nrf/spi_master \ 109 | $(SDK_ROOT)/components/drivers_nrf/hal \ 110 | $(SDK_ROOT)/components/drivers_nrf/rtc \ 111 | $(SDK_ROOT)/components/drivers_nrf/ppi \ 112 | $(SDK_ROOT)/components/drivers_nrf/swi \ 113 | $(SDK_ROOT)/components/drivers_nrf/clock \ 114 | $(SDK_ROOT)/components/drivers_nrf/usbd \ 115 | $(SDK_ROOT)/components/drivers_nrf/saadc \ 116 | $(SDK_ROOT)/components/drivers_nrf/pdm \ 117 | $(SDK_ROOT)/components/drivers_nrf/delay \ 118 | $(SDK_ROOT)/components/toolchain/cmsis/include \ 119 | $(SDK_ROOT)/components/softdevice/s132/headers/nrf52 \ 120 | $(SDK_ROOT)/components/drivers_nrf/timer \ 121 | $(SDK_ROOT)/components/drivers_nrf/pwm \ 122 | $(SDK_ROOT)/components/drivers_nrf/rng \ 123 | $(SDK_ROOT)/components/drivers_nrf/twi_master \ 124 | $(SDK_ROOT)/components/drivers_nrf/spi_master \ 125 | $(SDK_ROOT)/components/drivers_nrf/twis_slave \ 126 | $(SDK_ROOT)/components/drivers_nrf/lpcomp \ 127 | $(SDK_ROOT)/components/drivers_nrf/power \ 128 | $(SDK_ROOT)/components/drivers_nrf/qdec \ 129 | $(SDK_ROOT)/components/ble/common \ 130 | $(SDK_ROOT)/components/ble/ble_advertising \ 131 | $(SDK_ROOT)/components/ble/ble_dtm \ 132 | $(SDK_ROOT)/components/ble/ble_racp \ 133 | $(SDK_ROOT)/components/ble/peer_manager \ 134 | $(SDK_ROOT)/components/ble/ble_services/ble_ancs_c \ 135 | $(SDK_ROOT)/components/ble/ble_services/ble_ias_c \ 136 | $(SDK_ROOT)/components/ble/ble_services/ble_rscs_c \ 137 | $(SDK_ROOT)/components/ble/ble_services/ble_gls \ 138 | $(SDK_ROOT)/components/ble/ble_services/ble_bas_c \ 139 | $(SDK_ROOT)/components/ble/ble_services/ble_hrs_c \ 140 | $(SDK_ROOT)/components/ble/ble_services/ble_lls \ 141 | $(SDK_ROOT)/components/ble/ble_services/ble_tps \ 142 | $(SDK_ROOT)/components/ble/ble_services/ble_dis \ 143 | $(SDK_ROOT)/components/ble/ble_services/ble_hrs \ 144 | $(SDK_ROOT)/components/ble/ble_services/ble_bas \ 145 | $(SDK_ROOT)/components/ble/ble_services/ble_ans_c \ 146 | $(SDK_ROOT)/components/ble/ble_services/ble_rscs \ 147 | $(SDK_ROOT)/components/ble/ble_services/ble_nus \ 148 | $(SDK_ROOT)/components/ble/ble_services/ble_hids \ 149 | $(SDK_ROOT)/components/ble/ble_services/ble_lbs_c \ 150 | $(SDK_ROOT)/components/ble/ble_services/ble_nus_c \ 151 | $(SDK_ROOT)/components/ble/ble_services/ble_ias \ 152 | $(SDK_ROOT)/components/ble/ble_services/ble_lbs \ 153 | $(SDK_ROOT)/components/ble/ble_services/ble_hts \ 154 | $(SDK_ROOT)/components/ble/ble_services/ble_dfu \ 155 | $(SDK_ROOT)/components/ble/ble_services/ble_cscs \ 156 | $(SDK_ROOT)/components/ble/ble_services/ble_cts_c \ 157 | $(SDK_ROOT)/components/ble/nrf_ble_gatt \ 158 | $(SDK_ROOT)/components/ble/nrf_ble_qwr \ 159 | $(SDK_ROOT)/components/softdevice/s132/headers \ 160 | $(SDK_ROOT)/components/softdevice/s132/headers/nrf52 \ 161 | $(SDK_ROOT)/components/softdevice/common/softdevice_handler \ 162 | $(SDK_ROOT)/components/libraries/slip \ 163 | $(SDK_ROOT)/components/libraries/mem_manager \ 164 | $(SDK_ROOT)/components/libraries/usbd/class/cdc/acm \ 165 | $(SDK_ROOT)/components/libraries/usbd/class/hid/generic \ 166 | $(SDK_ROOT)/components/libraries/usbd/class/msc \ 167 | $(SDK_ROOT)/components/libraries/usbd/class/hid \ 168 | $(SDK_ROOT)/components/libraries/log \ 169 | $(SDK_ROOT)/components/libraries/pwm \ 170 | $(SDK_ROOT)/components/libraries/bsp \ 171 | $(SDK_ROOT)/components/libraries/fstorage \ 172 | $(SDK_ROOT)/components/libraries/gpiote \ 173 | $(SDK_ROOT)/components/libraries/queue \ 174 | $(SDK_ROOT)/components/libraries/csense_drv \ 175 | $(SDK_ROOT)/components/libraries/csense \ 176 | $(SDK_ROOT)/components/libraries/low_power_pwm \ 177 | $(SDK_ROOT)/components/libraries/hardfault \ 178 | $(SDK_ROOT)/components/libraries/uart \ 179 | $(SDK_ROOT)/components/libraries/hci \ 180 | $(SDK_ROOT)/components/libraries/usbd/class/hid/kbd \ 181 | $(SDK_ROOT)/components/libraries/spi_mngr \ 182 | $(SDK_ROOT)/components/libraries/strerror \ 183 | $(SDK_ROOT)/components/libraries/crc32 \ 184 | $(SDK_ROOT)/components/libraries/usbd/class/audio \ 185 | $(SDK_ROOT)/components/libraries/sensorsim \ 186 | $(SDK_ROOT)/components/libraries/fds \ 187 | $(SDK_ROOT)/components/libraries/twi \ 188 | $(SDK_ROOT)/components/libraries/timer \ 189 | $(SDK_ROOT)/components/libraries/button \ 190 | $(SDK_ROOT)/components/libraries/usbd \ 191 | $(SDK_ROOT)/components/libraries/log/src \ 192 | $(SDK_ROOT)/components/libraries/timer \ 193 | $(SDK_ROOT)/components/libraries/usbd/config \ 194 | $(SDK_ROOT)/components/libraries/usbd/class/cdc \ 195 | $(SDK_ROOT)/components/libraries/usbd/class/hid/mouse \ 196 | $(SDK_ROOT)/components/libraries/led_softblink \ 197 | $(SDK_ROOT)/components/libraries/experimental_section_vars \ 198 | $(SDK_ROOT)/components/libraries/crc16 \ 199 | $(SDK_ROOT)/components/libraries/util \ 200 | $(SDK_ROOT)/components/libraries/scheduler \ 201 | $(SDK_ROOT)/components/boards \ 202 | $(SDK_ROOT)/components/toolchain/cmsis/include \ 203 | $(SDK_ROOT)/components/libraries/ecc \ 204 | $(SDK_ROOT)/components \ 205 | ../config \ 206 | $(SDK_ROOT)/components/device \ 207 | $(SDK_ROOT)/components/toolchain \ 208 | $(SDK_ROOT)/components/toolchain/gcc \ 209 | $(SDK_ROOT)/external/segger_rtt \ 210 | 211 | # Libraries common to all targets 212 | LIB_FILES += \ 213 | $(SDK_ROOT)/components/toolchain/cmsis/dsp/GCC/libarm_cortexM4lf_math.a \ 214 | 215 | # C flags common to all targets 216 | CFLAGS += -DARM_MATH_CM4 217 | CFLAGS += -DBLE_STACK_SUPPORT_REQD 218 | CFLAGS += -DBOARD_D52_BA 219 | CFLAGS += -DCONFIG_GPIO_AS_PINRESET 220 | CFLAGS += -DNRF52 221 | CFLAGS += -DNRF52832_XXAA 222 | CFLAGS += -DNRF52_PAN_12 223 | CFLAGS += -DNRF52_PAN_15 224 | CFLAGS += -DNRF52_PAN_20 225 | CFLAGS += -DNRF52_PAN_31 226 | CFLAGS += -DNRF52_PAN_36 227 | CFLAGS += -DNRF52_PAN_51 228 | CFLAGS += -DNRF52_PAN_54 229 | CFLAGS += -DNRF52_PAN_55 230 | CFLAGS += -DNRF52_PAN_58 231 | CFLAGS += -DNRF52_PAN_64 232 | CFLAGS += -DNRF52_PAN_74 233 | CFLAGS += -DNRF_SD_BLE_API_VERSION=4 234 | CFLAGS += -DS132 235 | CFLAGS += -DNRF_LOG_USES_RTT=1 236 | #CFLAGS += -DSOFTDEVICE_PRESENT 237 | CFLAGS += -DSWI_DISABLE0 238 | CFLAGS += -D__HEAP_SIZE=0 239 | CFLAGS += -mcpu=cortex-m4 240 | CFLAGS += -mthumb -mabi=aapcs 241 | #CFLAGS += -Wall -Werror -O3 -g3 242 | CFLAGS += -Wall -ggdb #-Werror 243 | CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 244 | # keep every function in separate section, this allows linker to discard unused ones 245 | CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing 246 | CFLAGS += -fno-builtin --short-enums 247 | 248 | # C++ flags common to all targets 249 | CXXFLAGS += \ 250 | 251 | # Assembler flags common to all targets 252 | ASMFLAGS += -x assembler-with-cpp 253 | ASMFLAGS += -DBLE_STACK_SUPPORT_REQD 254 | ASMFLAGS += -DBOARD_D52_BA 255 | ASMFLAGS += -DCONFIG_GPIO_AS_PINRESET 256 | ASMFLAGS += -DNRF52 257 | ASMFLAGS += -DNRF52832_XXAA 258 | ASMFLAGS += -DNRF52_PAN_12 259 | ASMFLAGS += -DNRF52_PAN_15 260 | ASMFLAGS += -DNRF52_PAN_20 261 | ASMFLAGS += -DNRF52_PAN_31 262 | ASMFLAGS += -DNRF52_PAN_36 263 | ASMFLAGS += -DNRF52_PAN_51 264 | ASMFLAGS += -DNRF52_PAN_54 265 | ASMFLAGS += -DNRF52_PAN_55 266 | ASMFLAGS += -DNRF52_PAN_58 267 | ASMFLAGS += -DNRF52_PAN_64 268 | ASMFLAGS += -DNRF52_PAN_74 269 | ASMFLAGS += -DNRF_SD_BLE_API_VERSION=4 270 | ASMFLAGS += -DS132 271 | ASMFLAGS += -DSOFTDEVICE_PRESENT 272 | ASMFLAGS += -DSWI_DISABLE0 273 | ASMFLAGS += -D__HEAP_SIZE=0 274 | 275 | # Linker flags 276 | LDFLAGS += -mthumb -mabi=aapcs -L $(TEMPLATE_PATH) -T$(LINKER_SCRIPT) 277 | LDFLAGS += -mcpu=cortex-m4 278 | LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 279 | # let linker to dump unused sections 280 | LDFLAGS += -Wl,--gc-sections 281 | # use newlib in nano version 282 | LDFLAGS += --specs=nano.specs -lc -lnosys 283 | # Enable printf() to handle floats 284 | LDFLAGS += -u _printf_float 285 | 286 | .PHONY: $(TARGETS) default all clean help flash flash_softdevice 287 | 288 | # Default target - first one defined 289 | default: nrf52832_xxaa 290 | 291 | # Print all targets that can be built 292 | help: 293 | @echo following targets are available: 294 | @echo nrf52832_xxaa 295 | 296 | TEMPLATE_PATH := $(SDK_ROOT)/components/toolchain/gcc 297 | 298 | include $(TEMPLATE_PATH)/Makefile.common 299 | 300 | $(foreach target, $(TARGETS), $(call define_target, $(target))) 301 | 302 | # Flash the program 303 | flash: $(OUTPUT_DIRECTORY)/nrf52832_xxaa.hex 304 | @echo Flashing: $< 305 | $(NRF_ROOT)/nrfjprog --program $< -f nrf52 --sectorerase 306 | $(NRF_ROOT)/nrfjprog --reset -f nrf52 307 | 308 | # Flash softdevice 309 | flash_softdevice: 310 | @echo Flashing: s132_nrf52_4.0.2_softdevice.hex 311 | $(NRF_ROOT)/nrfjprog --program $(SDK_ROOT)/components/softdevice/s132/hex/s132_nrf52_4.0.2_softdevice.hex -f nrf52 --sectorerase 312 | $(NRF_ROOT)/nrfjprog --reset -f nrf52 313 | 314 | erase: 315 | $(NRF_ROOT)/nrfjprog --eraseall -f nrf52 316 | -------------------------------------------------------------------------------- /ics43434.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 24 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * Parts of this software, primarily the basic BLE control code, were derived or 30 | * directly copied from the Nordic reference implementations available in their SDK. 31 | * For those sections, the following license applies: 32 | * 33 | * Copyright (c) 2010 - 2017, Nordic Semiconductor ASA 34 | * All rights reserved. 35 | * 36 | * Redistribution and use in source and binary forms, with or without modification, 37 | * are permitted provided that the following conditions are met: 38 | * 39 | * 1. Redistributions of source code must retain the above copyright notice, this 40 | * list of conditions and the following disclaimer. 41 | * 42 | * 2. Redistributions in binary form, except as embedded into a Nordic 43 | * Semiconductor ASA integrated circuit in a product or a software update for 44 | * such product, must reproduce the above copyright notice, this list of 45 | * conditions and the following disclaimer in the documentation and/or other 46 | * materials provided with the distribution. 47 | * 48 | * 3. Neither the name of Nordic Semiconductor ASA nor the names of its 49 | * contributors may be used to endorse or promote products derived from this 50 | * software without specific prior written permission. 51 | * 52 | * 4. This software, with or without modification, must only be used with a 53 | * Nordic Semiconductor ASA integrated circuit. 54 | * 55 | * 5. Any software provided in binary form under this license must not be reverse 56 | * engineered, decompiled, modified and/or disassembled. 57 | * 58 | * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS 59 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 60 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 61 | * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE 62 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 63 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 64 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 67 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 68 | */ 69 | 70 | #include 71 | #include 72 | #include "nordic_common.h" 73 | #include "nrf.h" 74 | #include "app_error.h" 75 | #include "math.h" 76 | #include "boards.h" 77 | #include "app_timer.h" 78 | #include "nrf_drv_clock.h" 79 | #include "nrf_delay.h" 80 | #include "nrf_log.h" 81 | #include "nrf_log_ctrl.h" 82 | #include "app_pwm.h" 83 | #include "nrf_drv_i2s.h" 84 | #include "ics43434.h" 85 | #include "SEGGER_RTT.h" 86 | 87 | struct psd_bin_t 88 | { 89 | uint16_t freq; 90 | float32_t complex_mag; 91 | }; 92 | 93 | static uint32_t m_buffer_rx[I2S_BUFFER_SIZE]; 94 | static float32_t m_fft_input_f32[I2S_BUFFER_SIZE]; // FFT input array. Time domain 95 | static float32_t m_fft_output_f32[I2S_BUFFER_SIZE/2]; // FFT output data; individual scan. Frequency domain 96 | static struct psd_bin_t psd_f32[I2S_BUFFER_SIZE/2]; // FFT output data; scan average. Frequency domain 97 | static bool m_error_encountered; // I2S data callback error status 98 | static volatile bool pwm_ready_flag; // A PWM ready status 99 | static uint8_t psd_avg_count = 0; // FFT scan counter for scan averaging 100 | 101 | //We process every 20 datapackets - no idea how long that actually is. 102 | static uint8_t psd_avg_limit = 10; //(uint8_t)sample_time*AUDIO_RATE/1024; 103 | //20 = 1 full second of sampling 104 | //each packet is 50 ms 105 | 106 | static uint32_t m_ifft_flag = 0; // Flag that selects forward (0) or inverse (1) transform. 107 | static uint32_t m_do_bit_reverse = 1; // Flag that enables (1) or disables (0) bit reversal of output. 108 | 109 | fft_results_t results; 110 | 111 | void ICS_Get_Data(float * dest) { 112 | 113 | dest[0] = results.max; 114 | dest[1] = results.avg; 115 | dest[2] = results.freq[0]; 116 | dest[3] = results.freq[1]; 117 | dest[4] = results.freq[2]; 118 | dest[5] = results.complex_mag[0]; 119 | dest[6] = results.complex_mag[1]; 120 | dest[7] = results.complex_mag[2]; 121 | 122 | } 123 | 124 | APP_PWM_INSTANCE(PWM1,1); // Create the instance "PWM1" using TIMER1. 125 | APP_PWM_INSTANCE(PWM2,2); // Create the instance "PWM2" using TIMER2. 126 | 127 | static void pwm_ready_callback(uint32_t pwm_id) // PWM ready callback function 128 | { 129 | pwm_ready_flag = true; 130 | } 131 | 132 | /** 133 | * @brief Function for processing generated sine wave samples. 134 | * @param[in] p_input Pointer to input data array with complex number samples in time domain. 135 | * @param[in] p_input_struct Pointer to cfft instance structure describing input data. 136 | * @param[out] p_output Pointer to processed data (bins) array in frequency domain. 137 | * @param[in] output_size Processed data array size. 138 | */ 139 | static void fft_process(float32_t * p_input, 140 | const arm_cfft_instance_f32 * p_input_struct, 141 | float32_t * p_output, 142 | uint16_t output_size) 143 | { 144 | arm_cfft_f32(p_input_struct, p_input, m_ifft_flag, m_do_bit_reverse); // Use CFFT module to process the data 145 | arm_cmplx_mag_f32(p_input, p_output, output_size); // Calculate the magnitude at each bin using Complex Magnitude Module function 146 | } 147 | 148 | int psd_bin_comp(const void *elem1, const void *elem2) // PSD complex mag float comparison function for qsort 149 | { 150 | struct psd_bin_t *e1 = (struct psd_bin_t *)elem1; // Cast pointers to the PSD data structure 151 | struct psd_bin_t *e2 = (struct psd_bin_t *)elem2; // Sort WRT the complex mag 152 | if(e1->complex_mag < e2->complex_mag) // Returns -1 if elem1 < elem2 153 | return -1; 154 | return e1->complex_mag > e2->complex_mag; // Returns 0 if elem1 = elem2 and 1 if elem1 > elem2 155 | } 156 | 157 | static bool copy_samples(uint32_t const * p_buffer, uint16_t number_of_words) // I2S data callback read and FFT buffer write function 158 | { 159 | 160 | for(uint32_t i=0; i<(I2S_BUFFER_SIZE/2); i++) 161 | { 162 | m_fft_input_f32[2*i] = (float32_t)((int32_t)p_buffer[i]); 163 | m_fft_input_f32[(2*i + 1)] = 0.0f; 164 | } 165 | 166 | //SEGGER_RTT_WriteString(0, "bool copy_samples\n"); 167 | //SEGGER_RTT_printf(0, "samples: %d\n", psd_avg_count); 168 | //SEGGER_RTT_printf(0, "%f %f %f %f\r\n", m_fft_input_f32[0], m_fft_input_f32[2], m_fft_input_f32[4], m_fft_input_f32[6]); 169 | 170 | //here, we are adding new data 171 | fft_process(m_fft_input_f32, &arm_cfft_sR_f32_len1024, m_fft_output_f32, I2S_BUFFER_SIZE/2); 172 | 173 | /* Clear FPSCR register and clear pending FPU interrupts. This code is based on 174 | nRF5x_release_notes.txt in documentation folder. It is a necessary part of code when 175 | application using power saving mode and after handling FPU errors in polling mode. */ 176 | __set_FPSCR(__get_FPSCR() & ~(FPU_EXCEPTION_MASK)); // Clear any exceptions generated the FFT analysis 177 | 178 | (void) __get_FPSCR(); 179 | 180 | NVIC_ClearPendingIRQ(FPU_IRQn); 181 | 182 | for(uint32_t i=0; i= psd_avg_limit) 191 | { 192 | //SEGGER_RTT_WriteString(0, "Let's process!\n"); 193 | 194 | for(uint32_t i=0; i 0) 199 | { 200 | psd_f32[i].complex_mag *= 2.0f; 201 | } 202 | } 203 | 204 | psd_avg_count = 0; 205 | 206 | qsort(psd_f32, 512, sizeof(struct psd_bin_t), psd_bin_comp); // Sorts in ascending order of complex mag 207 | results.max = psd_f32[511].complex_mag; // Maximum is the last element in the sort 208 | results.avg = 0.0f; 209 | 210 | for(uint32_t i=0; i<512; i++) 211 | { 212 | results.avg += psd_f32[i].complex_mag; 213 | } 214 | 215 | results.avg /= 512.0f; 216 | 217 | for(uint8_t i=0; i<3; i++) // Load the four strongest PSD peaks into the results structure variable 218 | { 219 | results.freq[i] = (float)AUDIO_RATE*(float)psd_f32[511 - i].freq/1022.0f; 220 | results.complex_mag[i] = psd_f32[511 - i].complex_mag; 221 | } 222 | 223 | for(uint32_t i=0; i<512; i++) // Reset PSD results arrays for the next call 224 | { 225 | psd_f32[i].complex_mag = 0.0f; 226 | psd_f32[i].freq = i; 227 | } 228 | 229 | if ( SEGGER_MIC == 1 ) 230 | { 231 | SEGGER_RTT_printf(0, "Audio max: %d avg: %d\n", (uint32_t)(results.max), (uint32_t)(results.avg)); 232 | SEGGER_RTT_printf(0, "Audio f: %d %d %d\n", (uint32_t)(results.freq[0]), (uint32_t)(results.freq[1]), (uint32_t)(results.freq[2])); 233 | SEGGER_RTT_printf(0, "Audio m: %d %d %d\n", (uint32_t)(results.complex_mag[0]), (uint32_t)(results.complex_mag[1]), (uint32_t)(results.complex_mag[2])); 234 | } 235 | 236 | //we are done, turn system off. 237 | nrf_drv_i2s_stop(); 238 | 239 | } 240 | 241 | return true; 242 | } 243 | 244 | static void check_rx_data(uint32_t const * p_buffer, uint16_t number_of_words) 245 | { 246 | 247 | if (!m_error_encountered) 248 | { 249 | m_error_encountered = !copy_samples(p_buffer, number_of_words); 250 | } 251 | } 252 | 253 | // This is the I2S data handler - all data exchange related to the I2S transfers is done here. 254 | static void data_handler(uint32_t const * p_data_received, 255 | uint32_t * p_data_to_send, 256 | uint16_t number_of_words) 257 | { 258 | // Non-NULL value in 'p_data_received' indicates that a new portion of 259 | // data has been received and should be processed. 260 | if (p_data_received != NULL) 261 | { 262 | check_rx_data(p_data_received, number_of_words); 263 | } 264 | 265 | } 266 | 267 | void ICS_Sample(void) 268 | { 269 | ret_code_t err_code; 270 | 271 | err_code = nrf_drv_i2s_start(m_buffer_rx, NULL, I2S_BUFFER_SIZE, 0); // RX only; "NULL" XMIT buffer 272 | 273 | APP_ERROR_CHECK(err_code); 274 | 275 | memset(m_buffer_rx, 0xCC, sizeof(m_buffer_rx)); // Initialize I2S data callback buffer 276 | 277 | for(uint32_t i=0; i 64 | #include "sdk_errors.h" 65 | #include "nrf_drv_timer.h" 66 | #include "nrf_drv_common.h" 67 | #include "nrf_drv_ppi.h" 68 | #include "nrf_peripherals.h" 69 | 70 | #ifdef __cplusplus 71 | extern "C" { 72 | #endif 73 | 74 | #if defined(GPIOTE_FEATURE_SET_PRESENT) && defined(GPIOTE_FEATURE_CLR_PRESENT) 75 | #define GPIOTE_SET_CLEAR_TASKS 76 | #endif 77 | 78 | #define APP_PWM_NOPIN 0xFFFFFFFF 79 | 80 | /** @brief Number of channels for one timer instance (fixed to 2 due to timer properties).*/ 81 | #define APP_PWM_CHANNELS_PER_INSTANCE 2 82 | 83 | /**@brief Macro for creating a PWM instance. */ 84 | #define APP_PWM_INSTANCE(name, num) \ 85 | const nrf_drv_timer_t m_pwm_##name##_timer = NRF_DRV_TIMER_INSTANCE(num); \ 86 | app_pwm_cb_t m_pwm_##name##_cb; \ 87 | /*lint -e{545}*/ \ 88 | const app_pwm_t name = { \ 89 | .p_cb = &m_pwm_##name##_cb, \ 90 | .p_timer = &m_pwm_##name##_timer, \ 91 | } 92 | 93 | 94 | /**@brief PWM instance default configuration (1 channel). */ 95 | #define APP_PWM_DEFAULT_CONFIG_1CH(period_in_us, pin) \ 96 | { \ 97 | .pins = {pin, APP_PWM_NOPIN}, \ 98 | .pin_polarity = {APP_PWM_POLARITY_ACTIVE_LOW, APP_PWM_POLARITY_ACTIVE_LOW}, \ 99 | .num_of_channels = 1, \ 100 | .period_us = period_in_us \ 101 | } 102 | 103 | /**@brief PWM instance default configuration (2 channels). */ 104 | #define APP_PWM_DEFAULT_CONFIG_2CH(period_in_us, pin0, pin1) \ 105 | { \ 106 | .pins = {pin0, pin1}, \ 107 | .pin_polarity = {APP_PWM_POLARITY_ACTIVE_LOW, APP_PWM_POLARITY_ACTIVE_LOW}, \ 108 | .num_of_channels = 2, \ 109 | .period_us = period_in_us \ 110 | } 111 | 112 | typedef uint16_t app_pwm_duty_t; 113 | 114 | /** 115 | * @brief PWM callback that is executed when a PWM duty change has been completed. 116 | * 117 | * @param[in] pwm_id PWM instance ID. 118 | */ 119 | typedef void (* app_pwm_callback_t)(uint32_t); 120 | 121 | /** 122 | * @brief Channel polarity. 123 | */ 124 | typedef enum 125 | { 126 | APP_PWM_POLARITY_ACTIVE_LOW = 0, 127 | APP_PWM_POLARITY_ACTIVE_HIGH = 1 128 | } app_pwm_polarity_t; 129 | 130 | /**@brief PWM configuration structure used for initialization. */ 131 | typedef struct 132 | { 133 | uint32_t pins[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Pins configured as PWM output. 134 | app_pwm_polarity_t pin_polarity[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Polarity of active state on pin. 135 | uint32_t num_of_channels; //!< Number of channels that can be used. 136 | uint32_t period_us; //!< PWM signal output period to configure (in microseconds). 137 | } app_pwm_config_t; 138 | 139 | 140 | /** 141 | * @cond (NODOX) 142 | * @defgroup app_pwm_internal Auxiliary internal types declarations 143 | * @{ 144 | * @internal 145 | * 146 | * @brief Module for internal usage inside the library only 147 | * 148 | * There are some definitions that must be included in the header file because 149 | * of the way the library is set up. In this way, the are accessible to the user. 150 | * However, any functions and variables defined here may change at any time 151 | * without a warning, so you should not access them directly. 152 | */ 153 | 154 | /** 155 | * @brief PWM channel instance 156 | * 157 | * This structure holds all data needed by a single PWM channel. 158 | */ 159 | typedef struct 160 | { 161 | uint32_t gpio_pin; //!< Pin that is used by this PWM channel. 162 | uint32_t pulsewidth; //!< The copy of duty currently set (in ticks). 163 | nrf_ppi_channel_t ppi_channels[2]; //!< PPI channels used by the PWM channel to clear and set the output. 164 | app_pwm_polarity_t polarity; //!< The active state of the pin. 165 | uint8_t initialized; //!< The internal information if the selected channel was initialized. 166 | } app_pwm_channel_cb_t; 167 | 168 | /** 169 | * @brief Variable part of PWM instance 170 | * 171 | * This structure holds instance data that may change. 172 | */ 173 | typedef struct 174 | { 175 | app_pwm_channel_cb_t channels_cb[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Channels data 176 | uint32_t period; //!< Selected period in ticks 177 | app_pwm_callback_t p_ready_callback; //!< Callback function called on PWM readiness 178 | #ifdef GPIOTE_SET_CLEAR_TASKS 179 | nrf_ppi_channel_t ppi_channel; //!< PPI channel used temporary while changing duty 180 | #else 181 | nrf_ppi_channel_t ppi_channels[2]; //!< PPI channels used temporary while changing duty 182 | nrf_ppi_channel_group_t ppi_group; //!< PPI group used to synchronize changes on channels 183 | #endif 184 | nrf_drv_state_t state; //!< Current driver status 185 | } app_pwm_cb_t; 186 | /** @} 187 | * @endcond 188 | */ 189 | 190 | 191 | /**@brief PWM instance structure. */ 192 | typedef struct 193 | { 194 | app_pwm_cb_t *p_cb; //!< Pointer to control block internals. 195 | nrf_drv_timer_t const * const p_timer; //!< Timer used by this PWM instance. 196 | } app_pwm_t; 197 | 198 | /** 199 | * @brief Function for checking if the PWM instance is busy updating the duty cycle. 200 | * 201 | * @param[in] p_instance PWM instance. 202 | * 203 | * @retval True If the PWM instance is ready for duty cycle changes. 204 | * @retval False If a change operation is in progress. 205 | */ 206 | bool app_pwm_busy_check(app_pwm_t const * const p_instance); 207 | 208 | /** 209 | * @brief Function for initializing a PWM instance. 210 | * 211 | * @param[in] p_instance PWM instance. 212 | * @param[in] p_config Initial configuration. 213 | * @param[in] p_ready_callback Pointer to ready callback function (or NULL to disable). 214 | * 215 | * @retval NRF_SUCCESS If initialization was successful. 216 | * @retval NRF_ERROR_NO_MEM If there were not enough free resources. 217 | * @retval NRF_ERROR_INVALID_PARAM If an invalid configuration structure was passed. 218 | * @retval NRF_ERROR_INVALID_STATE If the timer/PWM is already in use or if initialization failed. 219 | */ 220 | ret_code_t app_pwm_init(app_pwm_t const * const p_instance, app_pwm_config_t const * const p_config, 221 | app_pwm_callback_t p_ready_callback); 222 | 223 | /** 224 | * @brief Function for initializing a PWM instance using timer ticks instead of microseconcs. 225 | * 226 | * @param[in] p_instance PWM instance. 227 | * @param[in] p_config Initial configuration. 228 | * @param[in] p_ready_callback Pointer to ready callback function (or NULL to disable). 229 | * 230 | * @retval NRF_SUCCESS If initialization was successful. 231 | * @retval NRF_ERROR_NO_MEM If there were not enough free resources. 232 | * @retval NRF_ERROR_INVALID_PARAM If an invalid configuration structure was passed. 233 | * @retval NRF_ERROR_INVALID_STATE If the timer/PWM is already in use or if initialization failed. 234 | */ 235 | ret_code_t app_pwm_ticks_init(app_pwm_t const * const p_instance, app_pwm_config_t const * const p_config, 236 | app_pwm_callback_t p_ready_callback); 237 | 238 | 239 | /** 240 | * @brief Function for uninitializing a PWM instance and releasing the allocated resources. 241 | * 242 | * @param[in] p_instance PWM instance. 243 | * 244 | * @retval NRF_SUCCESS If uninitialization was successful. 245 | * @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized. 246 | */ 247 | ret_code_t app_pwm_uninit(app_pwm_t const * const p_instance); 248 | 249 | /** 250 | * @brief Function for enabling a PWM instance after initialization. 251 | * 252 | * @param[in] p_instance PWM instance. 253 | */ 254 | void app_pwm_enable(app_pwm_t const * const p_instance); 255 | 256 | /** 257 | * @brief Function for disabling a PWM instance after initialization. 258 | * 259 | * @param[in] p_instance PWM instance. 260 | */ 261 | void app_pwm_disable(app_pwm_t const * const p_instance); 262 | 263 | /** 264 | * @brief Function for setting the PWM channel duty cycle in percents. 265 | * 266 | * A duty cycle change requires one full PWM clock period to finish. 267 | * If another change is attempted for any channel of given instance before 268 | * the current change is complete, the new attempt will result in the error 269 | * NRF_ERROR_BUSY. 270 | * 271 | * @param[in] p_instance PWM instance. 272 | * @param[in] channel Channel number. 273 | * @param[in] duty Duty cycle (0 - 100). 274 | * 275 | * @retval NRF_SUCCESS If the operation was successful. 276 | * @retval NRF_ERROR_BUSY If the PWM is not ready yet. 277 | * @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized. 278 | * 279 | */ 280 | ret_code_t app_pwm_channel_duty_set(app_pwm_t const * const p_instance, 281 | uint8_t channel, app_pwm_duty_t duty); 282 | 283 | /** 284 | * @brief Function for retrieving the PWM channel duty cycle in percents. 285 | * 286 | * @param[in] p_instance PWM instance. 287 | * @param[in] channel Channel number. 288 | * 289 | * @return Duty cycle value. 290 | */ 291 | app_pwm_duty_t app_pwm_channel_duty_get(app_pwm_t const * const p_instance, uint8_t channel); 292 | 293 | 294 | /** 295 | * @name Functions accessing values in ticks 296 | * 297 | * Auxiliary functions that allow to get values in actual timer ticks. 298 | * @{ 299 | */ 300 | 301 | /** 302 | * @brief Function for setting PWM channel duty cycle in clock ticks. 303 | * 304 | * @note Duty cycle changes require one full PWM clock period to finish. 305 | * Until that, the next change attempt (for any channel of given instance) 306 | * will result in an NRF_ERROR_BUSY error. 307 | * 308 | * @param[in] p_instance PWM instance. 309 | * @param[in] channel Channel number. 310 | * @param[in] ticks Number of PWM clock ticks. 311 | * 312 | * @retval NRF_SUCCESS If the operation was successful. 313 | * @retval NRF_ERROR_BUSY If PWM is not ready yet. 314 | * @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized. 315 | */ 316 | ret_code_t app_pwm_channel_duty_ticks_set(app_pwm_t const * const p_instance, 317 | uint8_t channel, 318 | uint16_t ticks); 319 | 320 | 321 | /** 322 | * @brief Function for retrieving the PWM channel duty cycle in ticks. 323 | * 324 | * This function retrieves the real, currently set duty cycle in ticks. 325 | * For one full PWM cycle the value might be different than the value set by the last 326 | * @ref app_pwm_channel_duty_ticks_set function call. 327 | * 328 | * @param[in] p_instance PWM instance. 329 | * @param[in] channel Channel number. 330 | * 331 | * @return Number of ticks set for selected channel. 332 | * 333 | */ 334 | uint16_t app_pwm_channel_duty_ticks_get(app_pwm_t const * const p_instance, uint8_t channel); 335 | 336 | /** 337 | * @brief Function for returning the number of ticks in a whole cycle. 338 | * 339 | * @param[in] p_instance PWM instance. 340 | * 341 | * @return Number of ticks that corresponds to 100% of the duty cycle. 342 | */ 343 | uint16_t app_pwm_cycle_ticks_get(app_pwm_t const * const p_instance); 344 | /** @} */ 345 | 346 | 347 | 348 | #ifdef __cplusplus 349 | } 350 | #endif 351 | 352 | #endif 353 | 354 | /** @} */ 355 | -------------------------------------------------------------------------------- /SPIFlash.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 24 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include "SPIFlash.h" 31 | #include "nrf_delay.h" 32 | #include "SEGGER_RTT.h" 33 | 34 | #define NRF_LOG_MODULE_NAME "FLASH" 35 | 36 | #define CMD_PAGE_PROGRAM ((uint8_t)0x02) 37 | #define CMD_WRITE_ENABLE ((uint8_t)0x06) 38 | #define CMD_READ_DATA ((uint8_t)0x03) 39 | #define CMD_READ_ID ((uint8_t)0x9F) 40 | #define CMD_READ_STATUS_REG ((uint8_t)0x05) 41 | 42 | #define SPI_INSTANCE_ID 1 43 | #define QUEUE_LENGTH 10 44 | 45 | //will return either a 1 or 0 if the bit is enabled 46 | #define CHECK_BIT(var,pos) (((var)>>(pos)) & 1) 47 | 48 | static const nrf_drv_spi_t m_spi_master_1 = NRF_DRV_SPI_INSTANCE(1); 49 | 50 | static uint8_t cmd[1] = { 0 }; 51 | 52 | static uint8_t tx4[4]; 53 | 54 | static uint8_t rx2[2]; 55 | static uint8_t rx4[4]; 56 | static uint8_t rx8[8]; 57 | static uint8_t rx256[256]; 58 | 59 | static uint8_t rxHalf[4+128]; 60 | static uint8_t txHalf[4+128]; 61 | 62 | static uint8_t rx20[16+4]; 63 | 64 | #define APP_IRQ_PRIORITY_LOW 3 //overrides definition elsewhere 65 | 66 | void FLASH_Init( void ) 67 | { 68 | nrf_drv_spi_config_t const spi_config = 69 | { 70 | .sck_pin = 7, 71 | .mosi_pin = 2, 72 | .miso_pin = 27, 73 | .ss_pin = 26, 74 | .irq_priority = APP_IRQ_PRIORITY_LOW, 75 | .orc = 0xFF, 76 | .frequency = NRF_DRV_SPI_FREQ_4M, 77 | .mode = NRF_DRV_SPI_MODE_0, 78 | .bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST, 79 | }; 80 | 81 | nrf_drv_spi_init(&m_spi_master_1, &spi_config, NULL, NULL); 82 | 83 | } 84 | 85 | void FLASH_Print_ID( void ) 86 | { 87 | cmd[0] = CMD_READ_ID; //Get JEDEC ID 88 | memset(rx4, 0, sizeof(rx4)); 89 | nrf_drv_spi_transfer(&m_spi_master_1, cmd, sizeof(cmd), rx4, sizeof(rx4)); 90 | SEGGER_RTT_printf(0, "MemID: %d Type: %d CAP: %d\r\n", rx4[1], rx4[2], rx4[3]); 91 | } 92 | 93 | uint8_t FLASH_Read_Status( void ) 94 | { 95 | memset(rx2, 0, sizeof(rx2)); 96 | cmd[0] = CMD_READ_STATUS_REG; 97 | nrf_drv_spi_transfer(&m_spi_master_1, cmd, sizeof(cmd), rx2, sizeof(rx2)); 98 | 99 | /* S0; 1 = busy 100 | S1; Write Enable Latch (WEL) is a read only bit in the status register 101 | that is set to 1 after executing a Write Enable Instruction. 102 | The WEL status bit is cleared to 0 when the device is write disabled 103 | */ 104 | 105 | if ( CHECK_BIT(rx2[1],0) ) { 106 | //NRF_LOG_DEBUG("SR: Busy\r\n") 107 | } else { 108 | //NRF_LOG_DEBUG("SR: Ready\r\n") 109 | }; 110 | 111 | if ( CHECK_BIT(rx2[1],1) ) { 112 | //NRF_LOG_DEBUG("SR: WEL\r\n") 113 | } else { 114 | //NRF_LOG_DEBUG("SR: NoWEL\r\n") 115 | }; 116 | 117 | return rx2[1]; 118 | } 119 | 120 | bool FLASH_Is_Write_Enabled( void ) 121 | { 122 | memset(rx2, 0, sizeof(rx2)); 123 | cmd[0] = CMD_READ_STATUS_REG; 124 | nrf_drv_spi_transfer(&m_spi_master_1, cmd, sizeof(cmd), rx2, sizeof(rx2)); 125 | 126 | //bool retval = true; 127 | 128 | //S1 == 1 Write Enable Latch (WEL) is a read only bit in the status register 129 | if ( CHECK_BIT(rx2[1],1) != 1) return false; 130 | //{ 131 | 132 | //NRF_LOG_DEBUG("FLASH_Is_Write_Enabled: False\r\n"); 133 | //} 134 | 135 | return true; 136 | } 137 | 138 | bool FLASH_Is_Busy( void ) 139 | { 140 | memset(rx2, 0, sizeof(rx2)); 141 | cmd[0] = CMD_READ_STATUS_REG; 142 | nrf_drv_spi_transfer(&m_spi_master_1, cmd, sizeof(cmd), rx2, sizeof(rx2)); 143 | 144 | //bool retval = false; 145 | 146 | if ( CHECK_BIT(rx2[1],0) == 1 ) return true; 147 | //{ 148 | // retval = true; 149 | //NRF_LOG_DEBUG("FLASH_Is_Busy!\r\n"); 150 | //} 151 | 152 | return false; 153 | } 154 | 155 | uint8_t * FLASH_Page_Read( uint16_t pageN ) 156 | { 157 | 158 | memset( tx4, 0, sizeof( tx4)); 159 | memset( rx256, 0, sizeof( rx256)); 160 | memset(rxHalf, 0, sizeof(rxHalf)); 161 | 162 | if ( pageN > 4095 ) { //memory has 4095 pages 163 | //NRF_LOG_DEBUG("FLASH_Page_Read: Out of bounds!\r\n") 164 | return rx256; 165 | }; 166 | 167 | int address = page_to_address( pageN ); 168 | 169 | //read the first 1/2 170 | tx4[0] = CMD_READ_DATA; 171 | tx4[1] = (address >> 16) & 0xFF; 172 | tx4[2] = (address >> 8) & 0xFF; 173 | tx4[3] = address & 0xFF; 174 | 175 | uint16_t i = 0; 176 | 177 | nrf_drv_spi_transfer(&m_spi_master_1, tx4, sizeof(tx4), rxHalf, sizeof(rxHalf)); 178 | for(i = 0; i < 128; i++) { rx256[i] = rxHalf[i+4]; }; 179 | 180 | tx4[3] = 128; 181 | memset(rxHalf, 0, sizeof(rxHalf)); 182 | 183 | nrf_drv_spi_transfer(&m_spi_master_1, tx4, sizeof(tx4), rxHalf, sizeof(rxHalf)); 184 | for(i = 128; i < 256; i++) { rx256[i] = rxHalf[(i-128)+4]; }; 185 | 186 | //NRF_LOG_HEXDUMP_DEBUG((uint8_t *)rx256, 256); 187 | 188 | //SEGGER_RTT_WriteString(0, "Reading now!"); 189 | 190 | for(i = 0; i < 16; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 191 | for(i = 16; i < 32; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 192 | for(i = 32; i < 48; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 193 | for(i = 48; i < 64; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 194 | 195 | nrf_delay_ms(100); 196 | 197 | for(i = 64; i < 80; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 198 | for(i = 80; i < 96; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 199 | for(i = 96; i < 112; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 200 | for(i = 112; i < 128; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 201 | 202 | nrf_delay_ms(100); 203 | 204 | for(i = 128; i < 144; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 205 | for(i = 144; i < 160; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 206 | for(i = 160; i < 176; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 207 | for(i = 176; i < 192; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 208 | 209 | nrf_delay_ms(100); 210 | 211 | for(i = 192; i < 208; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 212 | for(i = 208; i < 224; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 213 | for(i = 224; i < 240; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 214 | for(i = 240; i < 256; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; SEGGER_RTT_WriteString(0, "\n"); 215 | 216 | /* 217 | SEGGER_RTT_printf(0, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", \ 218 | rx256[i], rx256[i],rx256[i],rx256[i],rx256[i],rx256[i],rx256[i],rx256[i]) 219 | 220 | for(i = 0; i < 256; i++) { SEGGER_RTT_printf(0, "%d ", rx256[i]); }; 221 | 222 | SEGGER_RTT_WriteString(0, "\n"); 223 | */ 224 | return rx256; 225 | 226 | } 227 | 228 | void FLASH_Line_Read( uint16_t lineN, uint8_t *line ) 229 | { 230 | //this is now 4 larger 231 | //used to be 65535 232 | if ( lineN > 262140 ) { 233 | return; 234 | }; 235 | 236 | int address = (uint32_t)lineN * 16; 237 | 238 | tx4[0] = CMD_READ_DATA; 239 | tx4[1] = (address >> 16) & 0xFF; 240 | tx4[2] = (address >> 8) & 0xFF; 241 | tx4[3] = address & 0xFF; 242 | 243 | memset( rx20, 0, sizeof( rx20)); 244 | 245 | nrf_drv_spi_transfer(&m_spi_master_1, tx4, sizeof(tx4), rx20, sizeof(rx20)); 246 | 247 | for(uint16_t i = 4; i < 20; i++) line[i-4] = rx20[i]; 248 | 249 | } 250 | 251 | void FLASH_Page_WriteTest( uint16_t pageN ) 252 | { 253 | 254 | //old memory had 0-4095 pages, and each page has length 256 255 | //the new 4MB memory goes to 16384 256 | 257 | if ( pageN > 16384 ) { //memory has 16384 pages 258 | //NRF_LOG_DEBUG("FLASH_Page_Write: Out of bounds!\r\n") 259 | return; 260 | }; 261 | 262 | if ( !FLASH_Set_Write_Enable() ) { 263 | //NRF_LOG_DEBUG("FLASH_Page_Write: Write not enabled!\r\n") 264 | return; 265 | }; 266 | 267 | if ( FLASH_Is_Busy() ) { 268 | //NRF_LOG_DEBUG("FLASH_Page_Write: Busy!\r\n") 269 | return; 270 | }; 271 | 272 | if ( FLASH_Page_Is_Empty( pageN) == false ) { 273 | //NRF_LOG_DEBUG("FLASH_Page_Write: Page already contains data!\r\n") 274 | return; 275 | }; 276 | 277 | //NRF_LOG_DEBUG("Write looking good\r\n"); 278 | 279 | //the command and address 280 | int address = page_to_address( pageN ); 281 | 282 | memset(txHalf, 0, sizeof(txHalf)); 283 | 284 | txHalf[0] = CMD_PAGE_PROGRAM; 285 | txHalf[1] = (address >> 16) & 0xFF; 286 | txHalf[2] = (address >> 8) & 0xFF; 287 | txHalf[3] = address & 0xFF; 288 | 289 | uint16_t i = 0; 290 | 291 | //write the first 128 bytes 292 | //NRF_LOG_DEBUG("Write first part\r\n") 293 | for( i = 4; i < (128+4); i++ ) { txHalf[i] = i-4; }; 294 | nrf_drv_spi_transfer(&m_spi_master_1, txHalf, sizeof(txHalf), NULL, 0); 295 | 296 | if ( !FLASH_Set_Write_Enable() ) { 297 | //NRF_LOG_DEBUG("FLASH_Page_Write: Write not enabled!\r\n") 298 | return; 299 | }; 300 | 301 | //write the next 128 bytes 302 | txHalf[3] = 128; 303 | //NRF_LOG_DEBUG("Write second part\r\n") 304 | for( i = 4; i < (128+4); i++ ) { txHalf[i] = i-4; }; 305 | nrf_drv_spi_transfer(&m_spi_master_1, txHalf, sizeof(txHalf), NULL, 0); 306 | 307 | }; 308 | 309 | void FLASH_Page_Write( uint16_t pageN, uint8_t *wp ) 310 | { 311 | 312 | //memory has 0-4095 pages, and each page has length 256 313 | if ( pageN > 16384 - 1 ) { 314 | //NRF_LOG_DEBUG("FLASH_Page_Write: Out of bounds!\r\n") 315 | return; 316 | }; 317 | 318 | if ( !FLASH_Set_Write_Enable() ) { 319 | //NRF_LOG_DEBUG("FLASH_Page_Write: Write not enabled!\r\n") 320 | return; 321 | }; 322 | 323 | if ( FLASH_Is_Busy() ) { 324 | //NRF_LOG_DEBUG("FLASH_Page_Write: Busy!\r\n") 325 | return; 326 | }; 327 | 328 | if ( FLASH_Page_Is_Empty( pageN) == false ) { 329 | //NRF_LOG_DEBUG("FLASH_Page_Write: Page already contains data!\r\n") 330 | return; 331 | }; 332 | 333 | //NRF_LOG_DEBUG("Write looking good\r\n"); 334 | 335 | //the command and address 336 | int address = page_to_address( pageN ); 337 | 338 | memset(txHalf, 0, sizeof(txHalf)); 339 | 340 | txHalf[0] = CMD_PAGE_PROGRAM; 341 | txHalf[1] = (address >> 16) & 0xFF; 342 | txHalf[2] = (address >> 8) & 0xFF; 343 | txHalf[3] = address & 0xFF; 344 | 345 | uint16_t i = 0; 346 | 347 | //write the first 128 bytes 348 | for( i = 4; i < (128+4); i++ ) { txHalf[i] = wp[i-4]; }; 349 | nrf_drv_spi_transfer(&m_spi_master_1, txHalf, sizeof(txHalf), NULL, 0); 350 | 351 | //wait for at most 200 ms to make sure write completes 352 | for( i = 0; i < 10; i++ ) { 353 | nrf_delay_ms(20); 354 | if ( FLASH_Is_Busy() ) { 355 | //wait 356 | } else { 357 | break; 358 | } 359 | } 360 | 361 | //wait for at most 200 ms to make sure we are good for next write 362 | for( i = 0; i < 10; i++ ) { 363 | nrf_delay_ms(20); 364 | if ( FLASH_Set_Write_Enable() ) { 365 | break; 366 | } else { 367 | //NRF_LOG_DEBUG("Erase: Not able to write\r\n"); 368 | } 369 | } 370 | 371 | //write the next 128 bytes 372 | txHalf[3] = 128; 373 | for( i = 4; i < (128+4); i++ ) { txHalf[i] = wp[i-4+128]; }; 374 | nrf_drv_spi_transfer(&m_spi_master_1, txHalf, sizeof(txHalf), NULL, 0); 375 | 376 | }; 377 | 378 | bool FLASH_Page_Is_Empty( uint16_t pageN ) 379 | { 380 | 381 | if ( pageN > 16384 - 1 ) { //memory has 16384 pages 382 | //NRF_LOG_DEBUG("FLASH_PE: Out of bounds!\r\n") 383 | return false; //err on the side of safety 384 | }; 385 | 386 | memset(tx4, 0, sizeof(tx4)); 387 | memset(rx8, 0, sizeof(rx8)); 388 | 389 | int address = page_to_address( pageN ); 390 | 391 | tx4[0] = CMD_READ_DATA; 392 | tx4[1] = (address >> 16) & 0xFF; 393 | tx4[2] = (address >> 8) & 0xFF; 394 | tx4[3] = address & 0xFF; 395 | 396 | //NRF_LOG_HEXDUMP_DEBUG((uint8_t *)send4, 4); 397 | nrf_drv_spi_transfer(&m_spi_master_1, tx4, sizeof(tx4), rx8, sizeof(rx8)); 398 | 399 | uint16_t check = rx8[4] + rx8[5] + rx8[6] + rx8[7]; 400 | //empty = 255, so 255+255+255+255 = 1020 401 | //NRF_LOG_INFO("FLASH_PE Page:%d contains:%d\r\n", pageN, check); 402 | //NRF_LOG_HEXDUMP_DEBUG((uint8_t *)rx8, 8); 403 | 404 | if ( check == 1020 ) { 405 | //NRF_LOG_DEBUG("FLASH_PE: Page:%d is empty.\r\n", pageN); 406 | return true; 407 | } else { 408 | //NRF_LOG_DEBUG("FLASH_PE: Page:%d contains:%d\r\n", pageN, check); 409 | return false; 410 | } 411 | 412 | } 413 | 414 | uint16_t FLASH_Get_First_Available_Location( void ) 415 | { 416 | //this assumes that data were written contiguously 417 | uint16_t ds; 418 | 419 | for(ds = 0; ds < 16384; ds++) 420 | { 421 | //NRF_LOG_DEBUG("Testing page %d\r\n", ds); 422 | 423 | if( FLASH_Page_Is_Empty( ds ) ) 424 | { 425 | //NRF_LOG_DEBUG("Page %d is empty.\r\n", ds); 426 | return ds; 427 | } else { 428 | //keep searching 429 | //NRF_LOG_DEBUG("Page %d is full.\r\n", ds); 430 | }; 431 | }; 432 | 433 | //should never really get here 434 | //NRF_LOG_DEBUG("No memory available!\r\n", ds); 435 | return 16384; 436 | } 437 | 438 | //===================================== 439 | // convert a page number to a 24-bit address 440 | int page_to_address(int pn) 441 | { 442 | return(pn << 8); 443 | } 444 | 445 | //===================================== 446 | // convert a 24-bit address to a page number 447 | // get the 448 | int address_to_page(int addr) 449 | { 450 | return(addr >> 8); 451 | } 452 | 453 | //===================================== 454 | void FLASH_Reset( void ) 455 | { 456 | cmd[0] = 0xF0; 457 | nrf_drv_spi_transfer(&m_spi_master_1, cmd, sizeof(cmd), NULL, 0); 458 | } 459 | 460 | //===================================== 461 | void FLASH_Erase( void ) 462 | { 463 | if( !FLASH_Set_Write_Enable() ) { 464 | //NRF_LOG_DEBUG("Erase: Write not enabled\r\n"); 465 | } 466 | 467 | if ( FLASH_Is_Busy() ) { 468 | //NRF_LOG_DEBUG("Erase: FLASH is busy\r\n"); 469 | } 470 | 471 | //NRF_LOG_DEBUG("Erase: Erasing Flash\r\n"); 472 | 473 | cmd[0] = 0xC7; 474 | nrf_drv_spi_transfer(&m_spi_master_1, cmd, sizeof(cmd), NULL, 0); 475 | 476 | //wait for some 477 | while ( FLASH_Is_Busy() ) { 478 | nrf_delay_ms(1500); 479 | //NRF_LOG_DEBUG("Erase: FLASH is still busy\r\n"); 480 | } 481 | } 482 | 483 | //===================================== 484 | bool FLASH_Set_Write_Enable( void ) 485 | { 486 | bool enabled = false; 487 | cmd[0] = CMD_WRITE_ENABLE; 488 | nrf_drv_spi_transfer(&m_spi_master_1, cmd, sizeof(cmd), NULL, 0); 489 | 490 | if( FLASH_Is_Write_Enabled() ) { 491 | enabled = true; 492 | } else { 493 | enabled = false; 494 | //NRF_LOG_DEBUG("FLASH_Set_Write_Enable Fail\r\n"); 495 | }; 496 | 497 | return enabled; 498 | } -------------------------------------------------------------------------------- /ble_ma.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017, Stanford University 2 | * All rights reserved. 3 | * 4 | * The point of contact for the MENTAID wearables dev team is 5 | * Jan Liphardt (jan.liphardt@stanford.edu) 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. Neither the name of STANFORD UNIVERSITY nor the names of its contributors 15 | * may be used to endorse or promote products derived from this software 16 | * without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY STANFORD UNIVERSITY "AS IS" AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY OR ITS CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 24 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * Parts of this software, primarily the basic BLE control code, were derived or 30 | * directly copied from the Nordic reference implementations available in their SDK. 31 | * For those sections, the following license applies: 32 | * 33 | * Copyright (c) 2010 - 2017, Nordic Semiconductor ASA 34 | * All rights reserved. 35 | * 36 | * Redistribution and use in source and binary forms, with or without modification, 37 | * are permitted provided that the following conditions are met: 38 | * 39 | * 1. Redistributions of source code must retain the above copyright notice, this 40 | * list of conditions and the following disclaimer. 41 | * 42 | * 2. Redistributions in binary form, except as embedded into a Nordic 43 | * Semiconductor ASA integrated circuit in a product or a software update for 44 | * such product, must reproduce the above copyright notice, this list of 45 | * conditions and the following disclaimer in the documentation and/or other 46 | * materials provided with the distribution. 47 | * 48 | * 3. Neither the name of Nordic Semiconductor ASA nor the names of its 49 | * contributors may be used to endorse or promote products derived from this 50 | * software without specific prior written permission. 51 | * 52 | * 4. This software, with or without modification, must only be used with a 53 | * Nordic Semiconductor ASA integrated circuit. 54 | * 55 | * 5. Any software provided in binary form under this license must not be reverse 56 | * engineered, decompiled, modified and/or disassembled. 57 | * 58 | * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS 59 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 60 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 61 | * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE 62 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 63 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 64 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 67 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 68 | */ 69 | 70 | #include "sdk_common.h" 71 | #include "ble_ma.h" 72 | #include 73 | #include "ble_l2cap.h" 74 | #include "ble_srv_common.h" 75 | 76 | #define OPCODE_LENGTH 1 /**< Length of opcode inside Mentaid Measurement packet. */ 77 | #define HANDLE_LENGTH 2 /**< Length of handle inside Mentaid Measurement packet. */ 78 | #define MAX_MA_LEN (NRF_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Mentaid Measurement. */ 79 | #define INITIAL_VALUE_MA 0 /**< Initial Mentaid Measurement value. */ 80 | 81 | #define BLE_UUID_MENTAID_SERVICE 0x180D //use HRS for now... change later 82 | 83 | #define BLE_UUID_MENTAID_MEASUREMENT_CHAR 0x2A4A 84 | #define BLE_UUID_MENTAID_COMMAND_CHAR 0x2A4B 85 | #define BLE_UUID_MENTAID_STATUS_CHAR 0x2A4C 86 | 87 | /**@brief Function for handling the Connect event. 88 | * 89 | * @param[in] p_ma Mentaid Service structure. 90 | * @param[in] p_ble_evt Event received from the BLE stack. 91 | */ 92 | static void on_connect(ble_ma_t * p_ma, ble_evt_t * p_ble_evt) 93 | { 94 | p_ma->conn_handle = p_ble_evt->evt.gap_evt.conn_handle; 95 | } 96 | 97 | /**@brief Function for handling the Disconnect event. 98 | * 99 | * @param[in] p_ma Mentaid Service structure. 100 | * @param[in] p_ble_evt Event received from the BLE stack. 101 | */ 102 | static void on_disconnect(ble_ma_t * p_ma, ble_evt_t * p_ble_evt) 103 | { 104 | UNUSED_PARAMETER(p_ble_evt); 105 | p_ma->conn_handle = BLE_CONN_HANDLE_INVALID; 106 | } 107 | 108 | /**@brief Function for handling write events to the Mentaid Measurement characteristic. 109 | * 110 | * @param[in] p_ma Mentaid Service structure. 111 | * @param[in] p_evt_write Write event received from the BLE stack. 112 | */ 113 | static void on_ma_cccd_write(ble_ma_t * p_ma, ble_gatts_evt_write_t * p_evt_write) 114 | { 115 | if (p_evt_write->len == 2) 116 | { 117 | // CCCD written, update notification state 118 | if (p_ma->evt_handler != NULL) 119 | { 120 | ble_ma_evt_t evt; 121 | 122 | if (ble_srv_is_notification_enabled(p_evt_write->data)) 123 | { 124 | evt.evt_type = BLE_MA_EVT_NOTIFICATION_ENABLED; 125 | } 126 | else 127 | { 128 | evt.evt_type = BLE_MA_EVT_NOTIFICATION_DISABLED; 129 | } 130 | 131 | p_ma->evt_handler(p_ma, &evt); 132 | } 133 | } 134 | } 135 | 136 | /**@brief Function for handling the Write event. 137 | * 138 | * @param[in] p_ma Mentaid Service structure. 139 | * @param[in] p_ble_evt Event received from the BLE stack. 140 | */ 141 | static void on_write(ble_ma_t * p_ma, ble_evt_t * p_ble_evt) 142 | { 143 | ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write; 144 | 145 | if (p_evt_write->handle == p_ma->ma_handles.cccd_handle) 146 | { 147 | on_ma_cccd_write(p_ma, p_evt_write); 148 | } 149 | } 150 | 151 | void ble_ma_on_ble_evt(ble_ma_t * p_ma, ble_evt_t * p_ble_evt) 152 | { 153 | switch (p_ble_evt->header.evt_id) 154 | { 155 | case BLE_GAP_EVT_CONNECTED: 156 | on_connect(p_ma, p_ble_evt); 157 | break; 158 | 159 | case BLE_GAP_EVT_DISCONNECTED: 160 | on_disconnect(p_ma, p_ble_evt); 161 | break; 162 | 163 | case BLE_GATTS_EVT_WRITE: 164 | on_write(p_ma, p_ble_evt); 165 | break; 166 | 167 | default: 168 | // No implementation needed. 169 | break; 170 | } 171 | } 172 | 173 | /**@brief Function for encoding a Mentaid Measurement. 174 | * 175 | * @param[in] p_ma Mentaid Service structure. 176 | * @param[in] time etc Measurements to be encoded. 177 | * @param[out] p_encoded_buffer Buffer where the encoded data will be written. 178 | * 179 | * @return Size of encoded data. 180 | */ 181 | uint8_t ma_encode(ble_ma_t * p_ma, uint16_t time, uint8_t b8, uint8_t p1, uint8_t t1, 182 | uint8_t h1, uint16_t l_white, int16_t ax, int16_t ay, int16_t az, uint16_t storage, 183 | uint8_t * p_encoded_buffer) 184 | { 185 | uint8_t flags = 0; 186 | uint8_t len = 1; 187 | 188 | len += uint16_encode(time, &p_encoded_buffer[len]); 189 | 190 | p_encoded_buffer[3] = b8; 191 | p_encoded_buffer[4] = p1; 192 | p_encoded_buffer[5] = t1; 193 | p_encoded_buffer[6] = h1; 194 | 195 | len = 7; 196 | 197 | len += uint16_encode(l_white, &p_encoded_buffer[len]); 198 | len += uint16_encode(ax, &p_encoded_buffer[len]); 199 | len += uint16_encode(ay, &p_encoded_buffer[len]); 200 | len += uint16_encode(az, &p_encoded_buffer[len]); 201 | len += uint16_encode(storage, &p_encoded_buffer[len]); 202 | 203 | // Add flags 204 | p_encoded_buffer[0] = flags; 205 | 206 | return len; 207 | } 208 | 209 | /**@brief Function for adding the Mentaid Measurement characteristic. 210 | * 211 | * @param[in] p_ma Mentaid Service structure. 212 | * @param[in] p_ma_init Information needed to initialize the service. 213 | * 214 | * @return NRF_SUCCESS on success, otherwise an error code. 215 | */ 216 | static uint32_t mentaid_measurement_char_add(ble_ma_t * p_ma, const ble_ma_init_t * p_ma_init) 217 | { 218 | ble_gatts_char_md_t char_md; 219 | ble_gatts_attr_t attr_char_value; 220 | ble_uuid_t ble_uuid; 221 | ble_gatts_attr_md_t attr_md; 222 | 223 | uint8_t encoded_initial_ma[MAX_MA_LEN]; 224 | ble_gatts_attr_md_t cccd_md; 225 | memset(&cccd_md, 0, sizeof(cccd_md)); 226 | 227 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); 228 | cccd_md.write_perm = p_ma_init->ma_attr_md.cccd_write_perm; 229 | cccd_md.vloc = BLE_GATTS_VLOC_STACK; 230 | 231 | memset(&char_md, 0, sizeof(char_md)); 232 | 233 | char_md.char_props.notify = 1; 234 | 235 | static char user_desc[] = "Mentaid Data"; 236 | char_md.p_char_user_desc = (uint8_t *) user_desc; 237 | char_md.char_user_desc_size = strlen(user_desc); 238 | char_md.char_user_desc_max_size = strlen(user_desc); 239 | 240 | //char_md.p_char_user_desc = NULL; 241 | 242 | char_md.p_char_pf = NULL; 243 | char_md.p_user_desc_md = NULL; 244 | char_md.p_cccd_md = &cccd_md; 245 | char_md.p_sccd_md = NULL; 246 | 247 | BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_MENTAID_MEASUREMENT_CHAR); 248 | 249 | memset(&attr_md, 0, sizeof(attr_md)); 250 | 251 | attr_md.read_perm = p_ma_init->ma_attr_md.read_perm; 252 | attr_md.write_perm = p_ma_init->ma_attr_md.write_perm; 253 | attr_md.vloc = BLE_GATTS_VLOC_STACK; 254 | attr_md.rd_auth = 0; 255 | attr_md.wr_auth = 0; 256 | attr_md.vlen = 1; 257 | 258 | memset(&attr_char_value, 0, sizeof(attr_char_value)); 259 | 260 | attr_char_value.p_uuid = &ble_uuid; 261 | attr_char_value.p_attr_md = &attr_md; 262 | attr_char_value.init_len = 1; 263 | attr_char_value.init_offs = 0; 264 | attr_char_value.max_len = MAX_MA_LEN; 265 | attr_char_value.p_value = encoded_initial_ma; 266 | 267 | return sd_ble_gatts_characteristic_add(p_ma->service_handle, 268 | &char_md, 269 | &attr_char_value, 270 | &p_ma->ma_handles); 271 | } 272 | 273 | static uint32_t mentaid_status_char_add(ble_ma_t * p_ma, const ble_ma_init_t * p_ma_init) 274 | { 275 | ble_gatts_char_md_t char_md; 276 | ble_gatts_attr_t attr_char_value; 277 | ble_uuid_t ble_uuid; 278 | ble_gatts_attr_md_t attr_md; 279 | 280 | ble_gatts_attr_md_t cccd_md; 281 | memset(&cccd_md, 0, sizeof(cccd_md)); 282 | 283 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); 284 | cccd_md.write_perm = p_ma_init->ma_attr_md.cccd_write_perm; 285 | cccd_md.vloc = BLE_GATTS_VLOC_STACK; 286 | 287 | memset(&char_md, 0, sizeof(char_md)); 288 | 289 | char_md.char_props.notify = 1; 290 | 291 | static char user_desc[] = "Mentaid Status Notify"; 292 | char_md.p_char_user_desc = (uint8_t *) user_desc; 293 | char_md.char_user_desc_size = strlen(user_desc); 294 | char_md.char_user_desc_max_size = strlen(user_desc); 295 | 296 | char_md.p_char_pf = NULL; 297 | char_md.p_user_desc_md = NULL; 298 | char_md.p_cccd_md = &cccd_md; 299 | char_md.p_sccd_md = NULL; 300 | 301 | BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_MENTAID_STATUS_CHAR); 302 | 303 | memset(&attr_md, 0, sizeof(attr_md)); 304 | 305 | attr_md.read_perm = p_ma_init->status_attr_md.read_perm; 306 | attr_md.write_perm = p_ma_init->status_attr_md.write_perm; 307 | attr_md.vloc = BLE_GATTS_VLOC_STACK; 308 | attr_md.rd_auth = 0; 309 | attr_md.wr_auth = 0; 310 | attr_md.vlen = 1; 311 | 312 | memset(&attr_char_value, 0, sizeof(attr_char_value)); 313 | 314 | attr_char_value.p_uuid = &ble_uuid; 315 | attr_char_value.p_attr_md = &attr_md; 316 | attr_char_value.init_len = 1; 317 | attr_char_value.init_offs = 0; 318 | attr_char_value.max_len = 1; 319 | attr_char_value.p_value = (uint8_t*)12; 320 | 321 | return sd_ble_gatts_characteristic_add(p_ma->service_handle, 322 | &char_md, 323 | &attr_char_value, 324 | &p_ma->status_handles); 325 | } 326 | 327 | /**@brief Function for adding the Command characteristic. 328 | * 329 | * @param[in] p_ma Mentaid Service structure. 330 | * @param[in] p_ma_init Information needed to initialize the service. 331 | * 332 | * @return NRF_SUCCESS on success, otherwise an error code. 333 | */ 334 | static uint32_t mentaid_command_char_add(ble_ma_t * p_ma, const ble_ma_init_t * p_ma_init) 335 | { 336 | ble_gatts_char_md_t char_md; 337 | ble_gatts_attr_t attr_char_value; 338 | ble_uuid_t ble_uuid; 339 | ble_gatts_attr_md_t attr_md; 340 | 341 | memset(&char_md, 0, sizeof(char_md)); 342 | 343 | //phone does not need to be able to read this 344 | //char_md.char_props.read = 1; 345 | 346 | //UNSAFE UNSAFE UNSAFE CHECK CHECK CHECK 347 | //the phone can change this number 348 | char_md.char_props.write = 1; 349 | char_md.char_props.write_wo_resp = 0; 350 | 351 | static char user_desc[] = "Mentaid Command"; 352 | char_md.p_char_user_desc = (uint8_t *) user_desc; 353 | char_md.char_user_desc_size = strlen(user_desc); 354 | char_md.char_user_desc_max_size = strlen(user_desc); 355 | 356 | //char_md.p_char_user_desc = NULL; 357 | 358 | char_md.p_char_pf = NULL; 359 | 360 | char_md.p_user_desc_md = NULL; 361 | 362 | char_md.p_cccd_md = NULL; 363 | char_md.p_sccd_md = NULL; 364 | 365 | BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_MENTAID_COMMAND_CHAR); 366 | 367 | memset(&attr_md, 0, sizeof(attr_md)); 368 | 369 | attr_md.read_perm = p_ma_init->command_attr_md.read_perm; 370 | attr_md.write_perm = p_ma_init->command_attr_md.write_perm; 371 | 372 | attr_md.vloc = BLE_GATTS_VLOC_STACK; 373 | attr_md.rd_auth = 0; 374 | attr_md.wr_auth = 0; 375 | attr_md.vlen = 0; 376 | 377 | memset(&attr_char_value, 0, sizeof(attr_char_value)); 378 | 379 | attr_char_value.p_uuid = &ble_uuid; 380 | attr_char_value.p_attr_md = &attr_md; 381 | attr_char_value.init_len = 1; 382 | attr_char_value.init_offs = 0; 383 | attr_char_value.max_len = 1; 384 | 385 | //set better initial value 386 | //uint8_t encoded_sc[1]; 387 | //encoded_sc[0] = 0; 388 | attr_char_value.p_value = 0; 389 | 390 | return sd_ble_gatts_characteristic_add(p_ma->service_handle, 391 | &char_md, 392 | &attr_char_value, 393 | &p_ma->command_handles); 394 | } 395 | 396 | 397 | uint32_t ble_ma_init(ble_ma_t * p_ma, const ble_ma_init_t * p_ma_init) 398 | { 399 | uint32_t err_code; 400 | ble_uuid_t ble_uuid; 401 | 402 | // Initialize service structure 403 | p_ma->evt_handler = p_ma_init->evt_handler; 404 | 405 | p_ma->current_status = p_ma_init->current_status; 406 | 407 | p_ma->conn_handle = BLE_CONN_HANDLE_INVALID; 408 | 409 | p_ma->max_ma_len = MAX_MA_LEN; 410 | 411 | // Add service 412 | BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_MENTAID_SERVICE); 413 | 414 | err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, 415 | &ble_uuid, 416 | &p_ma->service_handle); 417 | 418 | if (err_code != NRF_SUCCESS) 419 | { 420 | return err_code; 421 | } 422 | 423 | // Add measurement characteristic 424 | err_code = mentaid_measurement_char_add(p_ma, p_ma_init); 425 | 426 | if (err_code != NRF_SUCCESS) 427 | { 428 | return err_code; 429 | } 430 | 431 | // Add command characteristic 432 | err_code = mentaid_command_char_add(p_ma, p_ma_init); 433 | 434 | if (err_code != NRF_SUCCESS) 435 | { 436 | return err_code; 437 | } 438 | 439 | // Add status characteristic 440 | err_code = mentaid_status_char_add(p_ma, p_ma_init); 441 | 442 | if (err_code != NRF_SUCCESS) 443 | { 444 | return err_code; 445 | } 446 | 447 | return NRF_SUCCESS; 448 | } 449 | 450 | uint32_t ma_measurement_send_16( ble_ma_t * p_ma, uint8_t * data ) 451 | { 452 | uint32_t err_code; 453 | 454 | // Send value if connected and notifying 455 | if (p_ma->conn_handle != BLE_CONN_HANDLE_INVALID) 456 | { 457 | uint8_t encoded_ma[MAX_MA_LEN]; 458 | uint16_t len = 17; 459 | 460 | uint16_t hvx_len; 461 | ble_gatts_hvx_params_t hvx_params; 462 | 463 | //should be 17 bytes long 464 | encoded_ma[0] = 0; //no flags 465 | 466 | for( uint8_t i = 1; i < len; i++ ) 467 | { 468 | encoded_ma[i] = data[i-1]; 469 | } 470 | 471 | hvx_len = len; 472 | 473 | memset(&hvx_params, 0, sizeof(hvx_params)); 474 | 475 | hvx_params.handle = p_ma->ma_handles.value_handle; 476 | hvx_params.type = BLE_GATT_HVX_NOTIFICATION; 477 | hvx_params.offset = 0; 478 | hvx_params.p_len = &hvx_len; 479 | hvx_params.p_data = encoded_ma; //this is the data packet 480 | 481 | err_code = sd_ble_gatts_hvx(p_ma->conn_handle, &hvx_params); 482 | 483 | if ((err_code == NRF_SUCCESS) && (hvx_len != len)) 484 | { 485 | err_code = NRF_ERROR_DATA_SIZE; 486 | } 487 | } 488 | else 489 | { 490 | err_code = NRF_ERROR_INVALID_STATE; 491 | } 492 | 493 | return err_code; 494 | } 495 | 496 | uint32_t ma_measurement_send(ble_ma_t * p_ma, uint16_t time, uint8_t b8, uint8_t p1, uint8_t t1, 497 | uint8_t h1, uint16_t l_white, int16_t ax, int16_t ay, int16_t az, uint16_t storage) 498 | { 499 | uint32_t err_code; 500 | 501 | // Send value if connected and notifying 502 | if (p_ma->conn_handle != BLE_CONN_HANDLE_INVALID) 503 | { 504 | uint8_t encoded_ma[MAX_MA_LEN]; 505 | uint16_t len; 506 | uint16_t hvx_len; 507 | ble_gatts_hvx_params_t hvx_params; 508 | 509 | len = ma_encode(p_ma, time, b8, p1, t1, h1, l_white, ax, ay, az, storage, encoded_ma); 510 | 511 | hvx_len = len; 512 | 513 | memset(&hvx_params, 0, sizeof(hvx_params)); 514 | 515 | hvx_params.handle = p_ma->ma_handles.value_handle; 516 | hvx_params.type = BLE_GATT_HVX_NOTIFICATION; 517 | hvx_params.offset = 0; 518 | hvx_params.p_len = &hvx_len; 519 | hvx_params.p_data = encoded_ma; //this is the data packet 520 | 521 | err_code = sd_ble_gatts_hvx(p_ma->conn_handle, &hvx_params); 522 | 523 | if ((err_code == NRF_SUCCESS) && (hvx_len != len)) 524 | { 525 | err_code = NRF_ERROR_DATA_SIZE; 526 | } 527 | } 528 | else 529 | { 530 | err_code = NRF_ERROR_INVALID_STATE; 531 | } 532 | 533 | return err_code; 534 | } 535 | 536 | uint32_t ma_status_send( ble_ma_t * p_ma, uint8_t status ) 537 | { 538 | uint32_t err_code; 539 | 540 | // Send value if connected and notifying 541 | if (p_ma->conn_handle != BLE_CONN_HANDLE_INVALID) 542 | { 543 | uint8_t encoded_ma[1]; 544 | encoded_ma[0] = status; 545 | 546 | uint16_t hvx_len; 547 | ble_gatts_hvx_params_t hvx_params; 548 | 549 | hvx_len = 1; 550 | 551 | memset(&hvx_params, 0, sizeof(hvx_params)); 552 | 553 | hvx_params.handle = p_ma->status_handles.value_handle; 554 | hvx_params.type = BLE_GATT_HVX_NOTIFICATION; 555 | hvx_params.offset = 0; 556 | hvx_params.p_len = &hvx_len; 557 | hvx_params.p_data = encoded_ma; //encoded_ma; //this is the data packet 558 | 559 | err_code = sd_ble_gatts_hvx(p_ma->conn_handle, &hvx_params); 560 | 561 | if ((err_code == NRF_SUCCESS) && (hvx_len != 1)) 562 | { 563 | err_code = NRF_ERROR_DATA_SIZE; 564 | } 565 | } 566 | else 567 | { 568 | err_code = NRF_ERROR_INVALID_STATE; 569 | } 570 | 571 | return err_code; 572 | } 573 | 574 | void ble_ma_on_gatt_evt(ble_ma_t * p_ma, nrf_ble_gatt_evt_t const * p_gatt_evt) 575 | { 576 | if ( (p_ma->conn_handle == p_gatt_evt->conn_handle) 577 | && (p_gatt_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)) 578 | { 579 | p_ma->max_ma_len = p_gatt_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH; 580 | } 581 | } 582 | 583 | -------------------------------------------------------------------------------- /app_pwm.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015 - 2017, Nordic Semiconductor ASA 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form, except as embedded into a Nordic 13 | * Semiconductor ASA integrated circuit in a product or a software update for 14 | * such product, must reproduce the above copyright notice, this list of 15 | * conditions and the following disclaimer in the documentation and/or other 16 | * materials provided with the distribution. 17 | * 18 | * 3. Neither the name of Nordic Semiconductor ASA nor the names of its 19 | * contributors may be used to endorse or promote products derived from this 20 | * software without specific prior written permission. 21 | * 22 | * 4. This software, with or without modification, must only be used with a 23 | * Nordic Semiconductor ASA integrated circuit. 24 | * 25 | * 5. Any software provided in binary form under this license must not be reverse 26 | * engineered, decompiled, modified and/or disassembled. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS 29 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 30 | * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE 31 | * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE 32 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 34 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 37 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | * 39 | */ 40 | #include "sdk_common.h" 41 | #if NRF_MODULE_ENABLED(APP_PWM) 42 | #include "app_pwm.h" 43 | #include "nrf_drv_timer.h" 44 | #include "nrf_drv_ppi.h" 45 | #include "nrf_drv_common.h" 46 | #include "nrf_drv_gpiote.h" 47 | #include "nrf_gpiote.h" 48 | #include "nrf_gpio.h" 49 | #include "app_util_platform.h" 50 | #include "nrf_assert.h" 51 | 52 | #define APP_PWM_CHANNEL_INITIALIZED 1 53 | #define APP_PWM_CHANNEL_UNINITIALIZED 0 54 | 55 | #define APP_PWM_CHANNEL_ENABLED 1 56 | #define APP_PWM_CHANNEL_DISABLED 0 57 | 58 | #define TIMER_PRESCALER_MAX 9 59 | #define TIMER_MAX_PULSEWIDTH_US_ON_16M 4095 60 | 61 | #ifndef GPIOTE_SET_CLEAR_TASKS 62 | #define APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE 2 63 | #endif 64 | #define APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL 2 65 | 66 | #define UNALLOCATED 0xFFFFFFFFUL 67 | #define BUSY_STATE_CHANGING 0xFE 68 | #define BUSY_STATE_IDLE 0xFF 69 | 70 | #define PWM_MAIN_CC_CHANNEL 2 71 | #define PWM_SECONDARY_CC_CHANNEL 3 72 | 73 | #ifdef GPIOTE_SET_CLEAR_TASKS 74 | static bool m_use_ppi_delay_workaround; 75 | #endif 76 | 77 | 78 | /** 79 | * @brief PWM busy status 80 | * 81 | * Stores the number of a channel being currently updated. 82 | * 83 | */ 84 | static volatile uint8_t m_pwm_busy[TIMER_COUNT]; 85 | 86 | 87 | /** 88 | * @brief New duty cycle value 89 | * 90 | * When the channel duty cycle reaches this value, the update process is complete. 91 | */ 92 | static volatile uint32_t m_pwm_target_value[TIMER_COUNT]; 93 | 94 | 95 | /** 96 | * @brief PWM ready counter 97 | * 98 | * The value in this counter is decremented in every PWM cycle after initiating the update. 99 | * If an event handler function was specified by the user, it is being called 100 | * after two cycle events (at least one full PWM cycle). 101 | */ 102 | volatile uint8_t m_pwm_ready_counter[TIMER_COUNT][APP_PWM_CHANNELS_PER_INSTANCE]; 103 | 104 | /** 105 | * @brief Pointers to instances 106 | * 107 | * This array connects any active timer instance number with the pointer to the PWM instance. 108 | * It is used by the interrupt runtime. 109 | */ 110 | static const app_pwm_t * m_instances[TIMER_COUNT]; 111 | 112 | // Macros for getting the polarity of given instance/channel. 113 | #define POLARITY_ACTIVE(INST,CH) (( ((INST)->p_cb)->channels_cb[(CH)].polarity == \ 114 | APP_PWM_POLARITY_ACTIVE_LOW)?(0):(1)) 115 | #define POLARITY_INACTIVE(INST,CH) (( ((INST)->p_cb)->channels_cb[(CH)].polarity == \ 116 | APP_PWM_POLARITY_ACTIVE_LOW)?(1):(0)) 117 | 118 | //lint -save -e534 119 | 120 | 121 | /** 122 | * @brief Workaround for PAN-73. 123 | * 124 | * @param[in] timer Timer. 125 | * @param[in] enable Enable or disable. 126 | */ 127 | static void pan73_workaround(NRF_TIMER_Type * p_timer, bool enable) 128 | { 129 | #ifndef GPIOTE_SET_CLEAR_TASKS 130 | if (p_timer == NRF_TIMER0) 131 | { 132 | *(uint32_t *)0x40008C0C = (enable ? 1 : 0); 133 | } 134 | else if (p_timer == NRF_TIMER1) 135 | { 136 | *(uint32_t *)0x40009C0C = (enable ? 1 : 0); 137 | } 138 | else if (p_timer == NRF_TIMER2) 139 | { 140 | *(uint32_t *)0x4000AC0C = (enable ? 1 : 0); 141 | } 142 | #else 143 | UNUSED_PARAMETER(p_timer); 144 | UNUSED_PARAMETER(enable); 145 | #endif 146 | } 147 | 148 | bool app_pwm_busy_check(app_pwm_t const * const p_instance) 149 | { 150 | uint8_t busy_state = (m_pwm_busy[p_instance->p_timer->instance_id]); 151 | bool busy = true; 152 | if (busy_state != BUSY_STATE_IDLE) 153 | { 154 | if (busy_state != BUSY_STATE_CHANGING) 155 | { 156 | if (nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) busy_state) 157 | == m_pwm_target_value[p_instance->p_timer->instance_id]) 158 | { 159 | m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE; 160 | busy = false; 161 | } 162 | } 163 | } 164 | else 165 | { 166 | busy = false; 167 | } 168 | return busy; 169 | } 170 | 171 | 172 | /** 173 | * @brief Function for enabling the IRQ for a given PWM instance. 174 | * 175 | * @param[in] p_instance PWM instance. 176 | */ 177 | __STATIC_INLINE void pwm_irq_enable(app_pwm_t const * const p_instance) 178 | { 179 | nrf_drv_timer_compare_int_enable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL); 180 | } 181 | 182 | 183 | /** 184 | * @brief Function for disabling the IRQ for a given PWM instance. 185 | * 186 | * @param[in] p_instance PWM instance. 187 | */ 188 | __STATIC_INLINE void pwm_irq_disable(app_pwm_t const * const p_instance) 189 | { 190 | nrf_drv_timer_compare_int_disable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL); 191 | } 192 | 193 | #ifndef GPIOTE_SET_CLEAR_TASKS 194 | /** 195 | * @brief Function for disabling PWM channel PPI. 196 | * 197 | * @param[in] p_instance PWM instance. 198 | */ 199 | __STATIC_INLINE void pwm_channel_ppi_disable(app_pwm_t const * const p_instance, uint8_t channel) 200 | { 201 | app_pwm_cb_t * p_cb = p_instance->p_cb; 202 | 203 | nrf_drv_ppi_channel_disable(p_cb->channels_cb[channel].ppi_channels[0]); 204 | nrf_drv_ppi_channel_disable(p_cb->channels_cb[channel].ppi_channels[1]); 205 | } 206 | 207 | 208 | /** 209 | * @brief Function for disabling PWM PPI. 210 | * 211 | * @param[in] p_instance PWM instance. 212 | */ 213 | __STATIC_INLINE void pwm_ppi_disable(app_pwm_t const * const p_instance) 214 | { 215 | app_pwm_cb_t * p_cb = p_instance->p_cb; 216 | 217 | nrf_drv_ppi_channel_disable(p_cb->ppi_channels[0]); 218 | nrf_drv_ppi_channel_disable(p_cb->ppi_channels[1]); 219 | } 220 | #endif 221 | 222 | /** 223 | * @brief This function is called on interrupt after duty set. 224 | * 225 | * @param[in] timer Timer used by PWM. 226 | * @param[in] timer_instance_id Timer index. 227 | */ 228 | void pwm_ready_tick(nrf_timer_event_t event_type, void * p_context) 229 | { 230 | uint32_t timer_instance_id = (uint32_t)p_context; 231 | uint8_t disable = 1; 232 | 233 | for (uint8_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel) 234 | { 235 | if (m_pwm_ready_counter[timer_instance_id][channel]) 236 | { 237 | --m_pwm_ready_counter[timer_instance_id][channel]; 238 | if (!m_pwm_ready_counter[timer_instance_id][channel]) 239 | { 240 | app_pwm_cb_t * p_cb = m_instances[timer_instance_id]->p_cb; 241 | p_cb->p_ready_callback(timer_instance_id); 242 | } 243 | else 244 | { 245 | disable = 0; 246 | } 247 | } 248 | } 249 | 250 | if (disable) 251 | { 252 | pwm_irq_disable(m_instances[timer_instance_id]); 253 | } 254 | } 255 | 256 | 257 | /** 258 | * @brief Function for resource de-allocation. 259 | * 260 | * @param[in] p_instance PWM instance. 261 | */ 262 | //lint -e{650} 263 | static void pwm_dealloc(app_pwm_t const * const p_instance) 264 | { 265 | app_pwm_cb_t * p_cb = p_instance->p_cb; 266 | 267 | #ifdef GPIOTE_SET_CLEAR_TASKS 268 | nrf_drv_ppi_channel_free(p_cb->ppi_channel); 269 | #else 270 | for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++i) 271 | { 272 | if (p_cb->ppi_channels[i] != (nrf_ppi_channel_t)(uint8_t)(UNALLOCATED)) 273 | { 274 | nrf_drv_ppi_channel_free(p_cb->ppi_channels[i]); 275 | } 276 | } 277 | if (p_cb->ppi_group != (nrf_ppi_channel_group_t)UNALLOCATED) 278 | { 279 | nrf_drv_ppi_group_free(p_cb->ppi_group); 280 | } 281 | #endif //GPIOTE_SET_CLEAR_TASKS 282 | for (uint8_t ch = 0; ch < APP_PWM_CHANNELS_PER_INSTANCE; ++ch) 283 | { 284 | for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL; ++i) 285 | { 286 | if (p_cb->channels_cb[ch].ppi_channels[i] != (nrf_ppi_channel_t)UNALLOCATED) 287 | { 288 | nrf_drv_ppi_channel_free(p_cb->channels_cb[ch].ppi_channels[i]); 289 | p_cb->channels_cb[ch].ppi_channels[i] = (nrf_ppi_channel_t)UNALLOCATED; 290 | } 291 | } 292 | if (p_cb->channels_cb[ch].gpio_pin != UNALLOCATED) 293 | { 294 | nrf_drv_gpiote_out_uninit(p_cb->channels_cb[ch].gpio_pin); 295 | p_cb->channels_cb[ch].gpio_pin = UNALLOCATED; 296 | } 297 | p_cb->channels_cb[ch].initialized = APP_PWM_CHANNEL_UNINITIALIZED; 298 | } 299 | nrf_drv_timer_uninit(p_instance->p_timer); 300 | return; 301 | } 302 | 303 | #ifndef GPIOTE_SET_CLEAR_TASKS 304 | /** 305 | * @brief PWM state transition from (0%, 100%) to 0% or 100%. 306 | * 307 | * @param[in] p_instance PWM instance. 308 | * @param[in] channel PWM channel number. 309 | * @param[in] ticks Number of clock ticks. 310 | */ 311 | static void pwm_transition_n_to_0or100(app_pwm_t const * const p_instance, 312 | uint8_t channel, uint16_t ticks) 313 | { 314 | app_pwm_cb_t * p_cb = p_instance->p_cb; 315 | app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel]; 316 | nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group; 317 | 318 | pwm_ppi_disable(p_instance); 319 | nrf_drv_ppi_group_clear(p_ppigrp); 320 | nrf_drv_ppi_channels_include_in_group( 321 | nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[0]) | 322 | nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[1]), 323 | p_ppigrp); 324 | 325 | if (!ticks) 326 | { 327 | nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0], 328 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel), 329 | nrf_drv_ppi_task_addr_group_disable_get(p_ppigrp)); 330 | nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 0, false); 331 | m_pwm_target_value[p_instance->p_timer->instance_id] = 332 | nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) channel); 333 | nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1], 334 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel), 335 | nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL)); 336 | } 337 | else 338 | { 339 | ticks = p_cb->period; 340 | nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0], 341 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL), 342 | nrf_drv_ppi_task_addr_group_disable_get(p_ppigrp)); 343 | // Set secondary CC channel to non-zero value: 344 | nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 1, false); 345 | m_pwm_target_value[p_instance->p_timer->instance_id] = 0; 346 | // The captured value will be equal to 0, because timer clear on main PWM CC channel compare is enabled. 347 | nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1], 348 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL), 349 | nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL)); 350 | } 351 | 352 | nrf_drv_ppi_channel_enable(p_cb->ppi_channels[0]); 353 | nrf_drv_ppi_channel_enable(p_cb->ppi_channels[1]); 354 | 355 | p_ch_cb->pulsewidth = ticks; 356 | m_pwm_busy[p_instance->p_timer->instance_id] = PWM_SECONDARY_CC_CHANNEL; 357 | } 358 | 359 | 360 | /** 361 | * @brief PWM state transition from (0%, 100%) to (0%, 100%). 362 | * 363 | * @param[in] p_instance PWM instance. 364 | * @param[in] channel PWM channel number. 365 | * @param[in] ticks Number of clock ticks. 366 | */ 367 | static void pwm_transition_n_to_m(app_pwm_t const * const p_instance, 368 | uint8_t channel, uint16_t ticks) 369 | { 370 | app_pwm_cb_t * p_cb = p_instance->p_cb; 371 | app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel]; 372 | nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group; 373 | 374 | pwm_ppi_disable(p_instance); 375 | nrf_drv_ppi_group_clear(p_ppigrp); 376 | nrf_drv_ppi_channels_include_in_group( 377 | nrf_drv_ppi_channel_to_mask(p_cb->ppi_channels[0]) | 378 | nrf_drv_ppi_channel_to_mask(p_cb->ppi_channels[1]), 379 | p_ppigrp); 380 | 381 | nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0], 382 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL), 383 | nrf_drv_timer_capture_task_address_get(p_instance->p_timer, channel)); 384 | 385 | 386 | if (ticks + ((nrf_timer_frequency_get(p_instance->p_timer->p_reg) == NRF_TIMER_FREQ_16MHz) ? 1 : 0) 387 | < p_ch_cb->pulsewidth) 388 | { 389 | // For lower value, we need one more transition. Timer task delay is included. 390 | // If prescaler is disabled, one tick must be added because of 1 PCLK16M clock cycle delay. 391 | nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1], 392 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL), 393 | nrf_drv_gpiote_out_task_addr_get(p_ch_cb->gpio_pin)); 394 | } 395 | else 396 | { 397 | nrf_drv_ppi_channel_remove_from_group(p_cb->ppi_channels[1], p_ppigrp); 398 | } 399 | p_ch_cb->pulsewidth = ticks; 400 | nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, ticks, false); 401 | nrf_drv_ppi_group_enable(p_ppigrp); 402 | 403 | m_pwm_target_value[p_instance->p_timer->instance_id] = ticks; 404 | m_pwm_busy[p_instance->p_timer->instance_id] = channel; 405 | } 406 | 407 | 408 | /** 409 | * @brief PWM state transition from 0% or 100% to (0%, 100%). 410 | * 411 | * @param[in] p_instance PWM instance. 412 | * @param[in] channel PWM channel number. 413 | * @param[in] ticks Number of clock ticks. 414 | */ 415 | static void pwm_transition_0or100_to_n(app_pwm_t const * const p_instance, 416 | uint8_t channel, uint16_t ticks) 417 | { 418 | app_pwm_cb_t * p_cb = p_instance->p_cb; 419 | app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel]; 420 | nrf_ppi_channel_group_t p_ppigrp = p_cb->ppi_group; 421 | nrf_timer_cc_channel_t pwm_ch_cc = (nrf_timer_cc_channel_t)(channel); 422 | 423 | pwm_ppi_disable(p_instance); 424 | pwm_channel_ppi_disable(p_instance, channel); 425 | 426 | nrf_drv_timer_compare(p_instance->p_timer, pwm_ch_cc, ticks, false); 427 | nrf_drv_ppi_group_clear(p_ppigrp); 428 | nrf_drv_ppi_channels_include_in_group( 429 | nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[0])| 430 | nrf_drv_ppi_channel_to_mask(p_ch_cb->ppi_channels[1]), 431 | p_ppigrp); 432 | 433 | if (!p_ch_cb->pulsewidth) 434 | { 435 | // Channel is at 0%. 436 | nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0], 437 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel), 438 | nrf_drv_ppi_task_addr_group_enable_get(p_ppigrp)); 439 | nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 0, false); 440 | m_pwm_target_value[p_instance->p_timer->instance_id] = 441 | nrf_drv_timer_capture_get(p_instance->p_timer, (nrf_timer_cc_channel_t) channel); 442 | nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1], 443 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel), 444 | nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL)); 445 | 446 | } 447 | else 448 | { 449 | // Channel is at 100%. 450 | nrf_drv_ppi_channel_assign(p_cb->ppi_channels[0], 451 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL), 452 | nrf_drv_ppi_task_addr_group_enable_get(p_ppigrp)); 453 | // Set secondary CC channel to non-zero value: 454 | nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_SECONDARY_CC_CHANNEL, 1, false); 455 | m_pwm_target_value[p_instance->p_timer->instance_id] = 0; 456 | // The captured value will be equal to 0, because timer clear on main PWM CC channel compare is enabled. 457 | nrf_drv_ppi_channel_assign(p_cb->ppi_channels[1], 458 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL), 459 | nrf_drv_timer_capture_task_address_get(p_instance->p_timer, PWM_SECONDARY_CC_CHANNEL)); 460 | } 461 | nrf_drv_ppi_channel_enable(p_cb->ppi_channels[0]); 462 | nrf_drv_ppi_channel_enable(p_cb->ppi_channels[1]); 463 | 464 | p_ch_cb->pulsewidth = ticks; 465 | m_pwm_busy[p_instance->p_timer->instance_id] = PWM_SECONDARY_CC_CHANNEL; 466 | } 467 | 468 | 469 | /** 470 | * @brief PWM state transition from 0% or 100% to 0% or 100%. 471 | * 472 | * @param[in] p_instance PWM instance. 473 | * @param[in] channel PWM channel number. 474 | * @param[in] ticks Number of clock ticks. 475 | */ 476 | static void pwm_transition_0or100_to_0or100(app_pwm_t const * const p_instance, 477 | uint8_t channel, uint16_t ticks) 478 | { 479 | app_pwm_cb_t * p_cb = p_instance->p_cb; 480 | app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel]; 481 | nrf_timer_cc_channel_t pwm_ch_cc = (nrf_timer_cc_channel_t)(channel); 482 | 483 | pwm_ppi_disable(p_instance); 484 | pwm_channel_ppi_disable(p_instance, channel); 485 | if (!ticks) 486 | { 487 | // Set to 0%. 488 | nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_INACTIVE(p_instance, channel)); 489 | } 490 | else if (ticks >= p_cb->period) 491 | { 492 | // Set to 100%. 493 | ticks = p_cb->period; 494 | nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_ACTIVE(p_instance, channel)); 495 | } 496 | nrf_drv_timer_compare(p_instance->p_timer, pwm_ch_cc, ticks, false); 497 | p_ch_cb->pulsewidth = ticks; 498 | 499 | m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE; 500 | return; 501 | } 502 | 503 | static void pwm_transition(app_pwm_t const * const p_instance, 504 | uint8_t channel, uint16_t ticks) 505 | { 506 | app_pwm_cb_t * p_cb = p_instance->p_cb; 507 | app_pwm_channel_cb_t * p_ch_cb = &p_instance->p_cb->channels_cb[channel]; 508 | 509 | // Pulse width change sequence: 510 | if (!p_ch_cb->pulsewidth || p_ch_cb->pulsewidth >= p_cb->period) 511 | { 512 | // Channel is disabled (0%) or at 100%. 513 | if (!ticks || ticks >= p_cb->period) 514 | { 515 | // Set to 0 or 100%. 516 | pwm_transition_0or100_to_0or100(p_instance, channel, ticks); 517 | } 518 | else 519 | { 520 | // Other value. 521 | pwm_transition_0or100_to_n(p_instance, channel, ticks); 522 | } 523 | } 524 | else 525 | { 526 | // Channel is at other value. 527 | if (!ticks || ticks >= p_cb->period) 528 | { 529 | // Disable channel (set to 0%) or set to 100%. 530 | pwm_transition_n_to_0or100(p_instance, channel, ticks); 531 | } 532 | else 533 | { 534 | // Set to any other value. 535 | pwm_transition_n_to_m(p_instance, channel, ticks); 536 | } 537 | } 538 | } 539 | #else //GPIOTE_SET_CLEAR_TASKS 540 | /** 541 | * @brief PWM state transition. 542 | * 543 | * @param[in] p_instance PWM instance. 544 | * @param[in] channel PWM channel number. 545 | * @param[in] ticks Number of clock ticks. 546 | */ 547 | static void pwm_transition(app_pwm_t const * const p_instance, 548 | uint8_t channel, uint16_t ticks) 549 | { 550 | app_pwm_cb_t * p_cb = p_instance->p_cb; 551 | app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel]; 552 | nrf_timer_cc_channel_t pwm_ch_cc = (nrf_timer_cc_channel_t)(channel); 553 | 554 | nrf_drv_ppi_channel_disable(p_cb->ppi_channel); 555 | 556 | if (!ticks) 557 | { 558 | nrf_drv_ppi_channel_disable(p_ch_cb->ppi_channels[1]); 559 | nrf_drv_ppi_channel_enable(p_ch_cb->ppi_channels[0]); 560 | m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE; 561 | } 562 | else if (ticks >= p_cb->period) 563 | { 564 | ticks = p_cb->period; 565 | nrf_drv_ppi_channel_disable(p_ch_cb->ppi_channels[0]); 566 | nrf_drv_ppi_channel_enable(p_ch_cb->ppi_channels[1]); 567 | m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE; 568 | } 569 | else 570 | { 571 | // Set to any other value. 572 | if ((p_ch_cb->pulsewidth != p_cb->period) && (p_ch_cb->pulsewidth != 0) && (ticks < p_ch_cb->pulsewidth)) 573 | { 574 | nrf_drv_timer_compare(p_instance->p_timer, (nrf_timer_cc_channel_t)PWM_SECONDARY_CC_CHANNEL, p_ch_cb->pulsewidth, false); 575 | nrf_drv_ppi_channel_assign(p_cb->ppi_channel, 576 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, (nrf_timer_cc_channel_t)PWM_SECONDARY_CC_CHANNEL), 577 | p_ch_cb->polarity ? nrf_drv_gpiote_clr_task_addr_get(p_ch_cb->gpio_pin) : nrf_drv_gpiote_set_task_addr_get(p_ch_cb->gpio_pin)); 578 | nrf_drv_ppi_channel_enable(p_cb->ppi_channel); 579 | m_pwm_busy[p_instance->p_timer->instance_id] = channel; 580 | m_pwm_target_value[p_instance->p_timer->instance_id] = ticks; 581 | } 582 | else 583 | { 584 | m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE; 585 | } 586 | 587 | nrf_drv_timer_compare(p_instance->p_timer, pwm_ch_cc, ticks, false); 588 | 589 | nrf_drv_ppi_channel_enable(p_ch_cb->ppi_channels[0]); 590 | nrf_drv_ppi_channel_enable(p_ch_cb->ppi_channels[1]); 591 | } 592 | p_ch_cb->pulsewidth = ticks; 593 | return; 594 | } 595 | #endif //GPIOTE_SET_CLEAR_TASKS 596 | 597 | ret_code_t app_pwm_channel_duty_ticks_set(app_pwm_t const * const p_instance, 598 | uint8_t channel, 599 | uint16_t ticks) 600 | { 601 | app_pwm_cb_t * p_cb = p_instance->p_cb; 602 | app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel]; 603 | 604 | ASSERT(channel < APP_PWM_CHANNELS_PER_INSTANCE); 605 | ASSERT(p_ch_cb->initialized == APP_PWM_CHANNEL_INITIALIZED); 606 | 607 | if (p_cb->state != NRF_DRV_STATE_POWERED_ON) 608 | { 609 | return NRF_ERROR_INVALID_STATE; 610 | } 611 | if (ticks == p_ch_cb->pulsewidth) 612 | { 613 | if (p_cb->p_ready_callback) 614 | { 615 | p_cb->p_ready_callback(p_instance->p_timer->instance_id); 616 | } 617 | return NRF_SUCCESS; // No action required. 618 | } 619 | if (app_pwm_busy_check(p_instance)) 620 | { 621 | return NRF_ERROR_BUSY; // PPI channels for synchronization are still in use. 622 | } 623 | 624 | m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_CHANGING; 625 | 626 | // Set new value. 627 | 628 | pwm_transition(p_instance, channel, ticks); 629 | 630 | if (p_instance->p_cb->p_ready_callback) 631 | { 632 | //PWM ready interrupt handler will be called after one full period. 633 | m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 2; 634 | pwm_irq_enable(p_instance); 635 | } 636 | return NRF_SUCCESS; 637 | } 638 | 639 | uint16_t app_pwm_channel_duty_ticks_get(app_pwm_t const * const p_instance, uint8_t channel) 640 | { 641 | app_pwm_cb_t * p_cb = p_instance->p_cb; 642 | app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel]; 643 | 644 | return p_ch_cb->pulsewidth; 645 | } 646 | 647 | uint16_t app_pwm_cycle_ticks_get(app_pwm_t const * const p_instance) 648 | { 649 | app_pwm_cb_t * p_cb = p_instance->p_cb; 650 | 651 | return (uint16_t)p_cb->period; 652 | } 653 | 654 | ret_code_t app_pwm_channel_duty_set(app_pwm_t const * const p_instance, 655 | uint8_t channel, app_pwm_duty_t duty) 656 | { 657 | uint32_t ticks = ((uint32_t)app_pwm_cycle_ticks_get(p_instance) * (uint32_t)duty) / 100UL; 658 | return app_pwm_channel_duty_ticks_set(p_instance, channel, ticks); 659 | } 660 | 661 | 662 | app_pwm_duty_t app_pwm_channel_duty_get(app_pwm_t const * const p_instance, uint8_t channel) 663 | { 664 | uint32_t value = ((uint32_t)app_pwm_channel_duty_ticks_get(p_instance, channel) * 100UL) \ 665 | / (uint32_t)app_pwm_cycle_ticks_get(p_instance); 666 | 667 | return (app_pwm_duty_t)value; 668 | } 669 | 670 | 671 | /** 672 | * @brief Function for initializing the PWM channel. 673 | * 674 | * @param[in] p_instance PWM instance. 675 | * @param[in] channel Channel number. 676 | * @param[in] pin GPIO pin number. 677 | * 678 | * @retval NRF_SUCCESS If initialization was successful. 679 | * @retval NRF_ERROR_NO_MEM If there were not enough free resources. 680 | * @retval NRF_ERROR_INVALID_STATE If the timer is already in use or initialization failed. 681 | */ 682 | static ret_code_t app_pwm_channel_init(app_pwm_t const * const p_instance, uint8_t channel, 683 | uint32_t pin, app_pwm_polarity_t polarity) 684 | { 685 | ASSERT(channel < APP_PWM_CHANNELS_PER_INSTANCE); 686 | app_pwm_cb_t * p_cb = p_instance->p_cb; 687 | app_pwm_channel_cb_t * p_channel_cb = &p_cb->channels_cb[channel]; 688 | 689 | if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED) 690 | { 691 | return NRF_ERROR_INVALID_STATE; 692 | } 693 | 694 | p_channel_cb->pulsewidth = 0; 695 | p_channel_cb->polarity = polarity; 696 | ret_code_t err_code; 697 | 698 | /* GPIOTE setup: */ 699 | nrf_drv_gpiote_out_config_t out_cfg = GPIOTE_CONFIG_OUT_TASK_TOGGLE( POLARITY_INACTIVE(p_instance, channel) ); 700 | err_code = nrf_drv_gpiote_out_init((nrf_drv_gpiote_pin_t)pin,&out_cfg); 701 | if (err_code != NRF_SUCCESS) 702 | { 703 | return NRF_ERROR_NO_MEM; 704 | } 705 | p_cb->channels_cb[channel].gpio_pin = pin; 706 | 707 | // Set output to inactive state. 708 | if (polarity) 709 | { 710 | nrf_gpio_pin_clear(pin); 711 | } 712 | else 713 | { 714 | nrf_gpio_pin_set(pin); 715 | } 716 | 717 | /* PPI setup: */ 718 | for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_CHANNEL; ++i) 719 | { 720 | if (nrf_drv_ppi_channel_alloc(&p_channel_cb->ppi_channels[i]) != NRF_SUCCESS) 721 | { 722 | return NRF_ERROR_NO_MEM; // Resource de-allocation is done by callee. 723 | } 724 | } 725 | 726 | nrf_drv_ppi_channel_disable(p_channel_cb->ppi_channels[0]); 727 | nrf_drv_ppi_channel_disable(p_channel_cb->ppi_channels[1]); 728 | 729 | #ifdef GPIOTE_SET_CLEAR_TASKS 730 | uint32_t deactivate_task_addr = polarity ? nrf_drv_gpiote_clr_task_addr_get(p_channel_cb->gpio_pin) : nrf_drv_gpiote_set_task_addr_get(p_channel_cb->gpio_pin); 731 | uint32_t activate_task_addr = polarity ? nrf_drv_gpiote_set_task_addr_get(p_channel_cb->gpio_pin) : nrf_drv_gpiote_clr_task_addr_get(p_channel_cb->gpio_pin); 732 | 733 | nrf_drv_ppi_channel_assign(p_channel_cb->ppi_channels[0], 734 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel), 735 | deactivate_task_addr); 736 | nrf_drv_ppi_channel_assign(p_channel_cb->ppi_channels[1], 737 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL), 738 | activate_task_addr); 739 | #else //GPIOTE_SET_CLEAR_TASKS 740 | nrf_drv_ppi_channel_assign(p_channel_cb->ppi_channels[0], 741 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, channel), 742 | nrf_drv_gpiote_out_task_addr_get(p_channel_cb->gpio_pin)); 743 | nrf_drv_ppi_channel_assign(p_channel_cb->ppi_channels[1], 744 | nrf_drv_timer_compare_event_address_get(p_instance->p_timer, PWM_MAIN_CC_CHANNEL), 745 | nrf_drv_gpiote_out_task_addr_get(p_channel_cb->gpio_pin)); 746 | #endif //GPIOTE_SET_CLEAR_TASKS 747 | p_channel_cb->initialized = APP_PWM_CHANNEL_INITIALIZED; 748 | m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 0; 749 | 750 | return NRF_SUCCESS; 751 | } 752 | 753 | 754 | /** 755 | * @brief Function for calculating target timer frequency, which will allow to set given period length. 756 | * 757 | * @param[in] period_us Desired period in microseconds. 758 | * 759 | * @retval Timer frequency. 760 | */ 761 | __STATIC_INLINE nrf_timer_frequency_t pwm_calculate_timer_frequency(uint32_t period_us) 762 | { 763 | uint32_t f = (uint32_t) NRF_TIMER_FREQ_16MHz; 764 | uint32_t min = (uint32_t) NRF_TIMER_FREQ_31250Hz; 765 | 766 | while ((period_us > TIMER_MAX_PULSEWIDTH_US_ON_16M) && (f < min)) 767 | { 768 | period_us >>= 1; 769 | ++f; 770 | } 771 | 772 | #ifdef GPIOTE_SET_CLEAR_TASKS 773 | if ((m_use_ppi_delay_workaround) && (f == (uint32_t) NRF_TIMER_FREQ_16MHz)) 774 | { 775 | f = (uint32_t) NRF_TIMER_FREQ_8MHz; 776 | } 777 | #endif // GPIOTE_SET_CLEAR_TASKS 778 | 779 | return (nrf_timer_frequency_t) f; 780 | } 781 | 782 | 783 | ret_code_t app_pwm_init(app_pwm_t const * const p_instance, app_pwm_config_t const * const p_config, 784 | app_pwm_callback_t p_ready_callback) 785 | { 786 | ASSERT(p_instance); 787 | 788 | if (!p_config) 789 | { 790 | return NRF_ERROR_INVALID_DATA; 791 | } 792 | 793 | app_pwm_cb_t * p_cb = p_instance->p_cb; 794 | 795 | if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED) 796 | { 797 | return NRF_ERROR_INVALID_STATE; 798 | } 799 | 800 | uint32_t err_code = nrf_drv_ppi_init(); 801 | if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_MODULE_ALREADY_INITIALIZED)) 802 | { 803 | return NRF_ERROR_NO_MEM; 804 | } 805 | 806 | 807 | if (!nrf_drv_gpiote_is_init()) 808 | { 809 | err_code = nrf_drv_gpiote_init(); 810 | if (err_code != NRF_SUCCESS) 811 | { 812 | return NRF_ERROR_INTERNAL; 813 | } 814 | } 815 | 816 | #ifdef GPIOTE_SET_CLEAR_TASKS 817 | if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30) 818 | { 819 | m_use_ppi_delay_workaround = false; 820 | } 821 | else 822 | { 823 | m_use_ppi_delay_workaround = true; 824 | } 825 | #endif 826 | 827 | // Innitialize resource status: 828 | #ifdef GPIOTE_SET_CLEAR_TASKS 829 | p_cb->ppi_channel = (nrf_ppi_channel_t)UNALLOCATED; 830 | #else 831 | p_cb->ppi_channels[0] = (nrf_ppi_channel_t)UNALLOCATED; 832 | p_cb->ppi_channels[1] = (nrf_ppi_channel_t)UNALLOCATED; 833 | p_cb->ppi_group = (nrf_ppi_channel_group_t)UNALLOCATED; 834 | #endif //GPIOTE_SET_CLEAR_TASKS 835 | 836 | for (uint8_t i = 0; i < APP_PWM_CHANNELS_PER_INSTANCE; ++i) 837 | { 838 | p_cb->channels_cb[i].initialized = APP_PWM_CHANNEL_UNINITIALIZED; 839 | p_cb->channels_cb[i].ppi_channels[0] = (nrf_ppi_channel_t)UNALLOCATED; 840 | p_cb->channels_cb[i].ppi_channels[1] = (nrf_ppi_channel_t)UNALLOCATED; 841 | p_cb->channels_cb[i].gpio_pin = UNALLOCATED; 842 | } 843 | 844 | // Allocate PPI channels and groups: 845 | 846 | #ifdef GPIOTE_SET_CLEAR_TASKS 847 | if (nrf_drv_ppi_channel_alloc(&p_cb->ppi_channel) != NRF_SUCCESS) 848 | { 849 | pwm_dealloc(p_instance); 850 | return NRF_ERROR_NO_MEM; 851 | } 852 | #else //GPIOTE_SET_CLEAR_TASKS 853 | if (nrf_drv_ppi_group_alloc(&p_cb->ppi_group) != NRF_SUCCESS) 854 | { 855 | pwm_dealloc(p_instance); 856 | return NRF_ERROR_NO_MEM; 857 | } 858 | 859 | for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++i) 860 | { 861 | if (nrf_drv_ppi_channel_alloc(&p_cb->ppi_channels[i]) != NRF_SUCCESS) 862 | { 863 | pwm_dealloc(p_instance); 864 | return NRF_ERROR_NO_MEM; 865 | } 866 | } 867 | #endif //GPIOTE_SET_CLEAR_TASKS 868 | // Initialize channels: 869 | for (uint8_t i = 0; i < APP_PWM_CHANNELS_PER_INSTANCE; ++i) 870 | { 871 | if (p_config->pins[i] != APP_PWM_NOPIN) 872 | { 873 | err_code = app_pwm_channel_init(p_instance, i, p_config->pins[i], p_config->pin_polarity[i]); 874 | if (err_code != NRF_SUCCESS) 875 | { 876 | pwm_dealloc(p_instance); 877 | return err_code; 878 | } 879 | app_pwm_channel_duty_ticks_set(p_instance, i, 0); 880 | } 881 | } 882 | 883 | // Initialize timer: 884 | nrf_timer_frequency_t timer_freq = pwm_calculate_timer_frequency(p_config->period_us); 885 | nrf_drv_timer_config_t timer_cfg = { 886 | .frequency = timer_freq, 887 | .mode = NRF_TIMER_MODE_TIMER, 888 | .bit_width = NRF_TIMER_BIT_WIDTH_16, 889 | .interrupt_priority = APP_IRQ_PRIORITY_LOWEST, 890 | .p_context = (void *) (uint32_t) p_instance->p_timer->instance_id 891 | }; 892 | err_code = nrf_drv_timer_init(p_instance->p_timer, &timer_cfg, 893 | pwm_ready_tick); 894 | if (err_code != NRF_SUCCESS) 895 | { 896 | pwm_dealloc(p_instance); 897 | return err_code; 898 | } 899 | 900 | uint32_t ticks = nrf_drv_timer_us_to_ticks(p_instance->p_timer, p_config->period_us); 901 | p_cb->period = ticks; 902 | nrf_drv_timer_clear(p_instance->p_timer); 903 | nrf_drv_timer_extended_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_MAIN_CC_CHANNEL, 904 | ticks, NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK, true); 905 | nrf_drv_timer_compare_int_disable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL); 906 | 907 | p_cb->p_ready_callback = p_ready_callback; 908 | m_instances[p_instance->p_timer->instance_id] = p_instance; 909 | m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE; 910 | p_cb->state = NRF_DRV_STATE_INITIALIZED; 911 | 912 | return NRF_SUCCESS; 913 | } 914 | 915 | 916 | ret_code_t app_pwm_ticks_init(app_pwm_t const * const p_instance, app_pwm_config_t const * const p_config, 917 | app_pwm_callback_t p_ready_callback) 918 | { 919 | ASSERT(p_instance); 920 | 921 | if (!p_config) 922 | { 923 | return NRF_ERROR_INVALID_DATA; 924 | } 925 | 926 | app_pwm_cb_t * p_cb = p_instance->p_cb; 927 | 928 | if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED) 929 | { 930 | return NRF_ERROR_INVALID_STATE; 931 | } 932 | 933 | uint32_t err_code = nrf_drv_ppi_init(); 934 | if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_MODULE_ALREADY_INITIALIZED)) 935 | { 936 | return NRF_ERROR_NO_MEM; 937 | } 938 | 939 | 940 | if (!nrf_drv_gpiote_is_init()) 941 | { 942 | err_code = nrf_drv_gpiote_init(); 943 | if (err_code != NRF_SUCCESS) 944 | { 945 | return NRF_ERROR_INTERNAL; 946 | } 947 | } 948 | 949 | #ifdef GPIOTE_SET_CLEAR_TASKS 950 | if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30) 951 | { 952 | m_use_ppi_delay_workaround = false; 953 | } 954 | else 955 | { 956 | m_use_ppi_delay_workaround = true; 957 | } 958 | #endif 959 | 960 | // Innitialize resource status: 961 | #ifdef GPIOTE_SET_CLEAR_TASKS 962 | p_cb->ppi_channel = (nrf_ppi_channel_t)UNALLOCATED; 963 | #else 964 | p_cb->ppi_channels[0] = (nrf_ppi_channel_t)UNALLOCATED; 965 | p_cb->ppi_channels[1] = (nrf_ppi_channel_t)UNALLOCATED; 966 | p_cb->ppi_group = (nrf_ppi_channel_group_t)UNALLOCATED; 967 | #endif //GPIOTE_SET_CLEAR_TASKS 968 | 969 | for (uint8_t i = 0; i < APP_PWM_CHANNELS_PER_INSTANCE; ++i) 970 | { 971 | p_cb->channels_cb[i].initialized = APP_PWM_CHANNEL_UNINITIALIZED; 972 | p_cb->channels_cb[i].ppi_channels[0] = (nrf_ppi_channel_t)UNALLOCATED; 973 | p_cb->channels_cb[i].ppi_channels[1] = (nrf_ppi_channel_t)UNALLOCATED; 974 | p_cb->channels_cb[i].gpio_pin = UNALLOCATED; 975 | } 976 | 977 | // Allocate PPI channels and groups: 978 | 979 | #ifdef GPIOTE_SET_CLEAR_TASKS 980 | if (nrf_drv_ppi_channel_alloc(&p_cb->ppi_channel) != NRF_SUCCESS) 981 | { 982 | pwm_dealloc(p_instance); 983 | return NRF_ERROR_NO_MEM; 984 | } 985 | #else //GPIOTE_SET_CLEAR_TASKS 986 | if (nrf_drv_ppi_group_alloc(&p_cb->ppi_group) != NRF_SUCCESS) 987 | { 988 | pwm_dealloc(p_instance); 989 | return NRF_ERROR_NO_MEM; 990 | } 991 | 992 | for (uint8_t i = 0; i < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++i) 993 | { 994 | if (nrf_drv_ppi_channel_alloc(&p_cb->ppi_channels[i]) != NRF_SUCCESS) 995 | { 996 | pwm_dealloc(p_instance); 997 | return NRF_ERROR_NO_MEM; 998 | } 999 | } 1000 | #endif //GPIOTE_SET_CLEAR_TASKS 1001 | // Initialize channels: 1002 | for (uint8_t i = 0; i < APP_PWM_CHANNELS_PER_INSTANCE; ++i) 1003 | { 1004 | if (p_config->pins[i] != APP_PWM_NOPIN) 1005 | { 1006 | err_code = app_pwm_channel_init(p_instance, i, p_config->pins[i], p_config->pin_polarity[i]); 1007 | if (err_code != NRF_SUCCESS) 1008 | { 1009 | pwm_dealloc(p_instance); 1010 | return err_code; 1011 | } 1012 | app_pwm_channel_duty_ticks_set(p_instance, i, 0); 1013 | } 1014 | } 1015 | 1016 | // Initialize timer: 1017 | nrf_timer_frequency_t timer_freq = NRF_TIMER_FREQ_16MHz; // Hard-set timer clock to 16MHz 1018 | nrf_drv_timer_config_t timer_cfg = { 1019 | .frequency = timer_freq, 1020 | .mode = NRF_TIMER_MODE_TIMER, 1021 | .bit_width = NRF_TIMER_BIT_WIDTH_16, 1022 | .interrupt_priority = APP_IRQ_PRIORITY_LOWEST, 1023 | .p_context = (void *) (uint32_t) p_instance->p_timer->instance_id 1024 | }; 1025 | err_code = nrf_drv_timer_init(p_instance->p_timer, &timer_cfg, 1026 | pwm_ready_tick); 1027 | if (err_code != NRF_SUCCESS) 1028 | { 1029 | pwm_dealloc(p_instance); 1030 | return err_code; 1031 | } 1032 | 1033 | //uint32_t ticks = nrf_drv_timer_us_to_ticks(p_instance->p_timer, p_config->period_us); 1034 | uint32_t ticks = p_config->period_us; 1035 | p_cb->period = ticks; 1036 | nrf_drv_timer_clear(p_instance->p_timer); 1037 | nrf_drv_timer_extended_compare(p_instance->p_timer, (nrf_timer_cc_channel_t) PWM_MAIN_CC_CHANNEL, 1038 | ticks, NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK, true); 1039 | nrf_drv_timer_compare_int_disable(p_instance->p_timer, PWM_MAIN_CC_CHANNEL); 1040 | 1041 | p_cb->p_ready_callback = p_ready_callback; 1042 | m_instances[p_instance->p_timer->instance_id] = p_instance; 1043 | m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE; 1044 | p_cb->state = NRF_DRV_STATE_INITIALIZED; 1045 | 1046 | return NRF_SUCCESS; 1047 | } 1048 | 1049 | 1050 | 1051 | void app_pwm_enable(app_pwm_t const * const p_instance) 1052 | { 1053 | app_pwm_cb_t * p_cb = p_instance->p_cb; 1054 | 1055 | ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED); 1056 | 1057 | for (uint32_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel) 1058 | { 1059 | app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel]; 1060 | m_pwm_ready_counter[p_instance->p_timer->instance_id][channel] = 0; 1061 | if (p_ch_cb->initialized) 1062 | { 1063 | nrf_drv_gpiote_out_task_force(p_ch_cb->gpio_pin, POLARITY_INACTIVE(p_instance, channel)); 1064 | nrf_drv_gpiote_out_task_enable(p_ch_cb->gpio_pin); 1065 | p_ch_cb->pulsewidth = 0; 1066 | } 1067 | } 1068 | m_pwm_busy[p_instance->p_timer->instance_id] = BUSY_STATE_IDLE; 1069 | 1070 | pan73_workaround(p_instance->p_timer->p_reg, true); 1071 | 1072 | nrf_drv_timer_clear(p_instance->p_timer); 1073 | nrf_drv_timer_enable(p_instance->p_timer); 1074 | 1075 | p_cb->state = NRF_DRV_STATE_POWERED_ON; 1076 | return; 1077 | } 1078 | 1079 | 1080 | void app_pwm_disable(app_pwm_t const * const p_instance) 1081 | { 1082 | app_pwm_cb_t * p_cb = p_instance->p_cb; 1083 | 1084 | ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED); 1085 | 1086 | nrf_drv_timer_disable(p_instance->p_timer); 1087 | pwm_irq_disable(p_instance); 1088 | 1089 | #ifdef GPIOTE_SET_CLEAR_TASKS 1090 | nrf_drv_ppi_channel_disable(p_cb->ppi_channel); 1091 | #else 1092 | for (uint8_t ppi_channel = 0; ppi_channel < APP_PWM_REQUIRED_PPI_CHANNELS_PER_INSTANCE; ++ppi_channel) 1093 | { 1094 | nrf_drv_ppi_channel_disable(p_cb->ppi_channels[ppi_channel]); 1095 | } 1096 | #endif //GPIOTE_SET_CLEAR_TASKS 1097 | 1098 | for (uint8_t channel = 0; channel < APP_PWM_CHANNELS_PER_INSTANCE; ++channel) 1099 | { 1100 | app_pwm_channel_cb_t * p_ch_cb = &p_cb->channels_cb[channel]; 1101 | if (p_ch_cb->initialized) 1102 | { 1103 | uint8_t polarity = POLARITY_INACTIVE(p_instance, channel); 1104 | if (polarity) 1105 | { 1106 | nrf_gpio_pin_set(p_ch_cb->gpio_pin); 1107 | } 1108 | else 1109 | { 1110 | nrf_gpio_pin_clear(p_ch_cb->gpio_pin); 1111 | } 1112 | nrf_drv_gpiote_out_task_disable(p_ch_cb->gpio_pin); 1113 | nrf_drv_ppi_channel_disable(p_ch_cb->ppi_channels[0]); 1114 | nrf_drv_ppi_channel_disable(p_ch_cb->ppi_channels[1]); 1115 | } 1116 | } 1117 | 1118 | pan73_workaround(p_instance->p_timer->p_reg, false); 1119 | 1120 | p_cb->state = NRF_DRV_STATE_INITIALIZED; 1121 | return; 1122 | } 1123 | 1124 | 1125 | ret_code_t app_pwm_uninit(app_pwm_t const * const p_instance) 1126 | { 1127 | app_pwm_cb_t * p_cb = p_instance->p_cb; 1128 | 1129 | if (p_cb->state == NRF_DRV_STATE_POWERED_ON) 1130 | { 1131 | app_pwm_disable(p_instance); 1132 | } 1133 | else if (p_cb->state == NRF_DRV_STATE_UNINITIALIZED) 1134 | { 1135 | return NRF_ERROR_INVALID_STATE; 1136 | } 1137 | pwm_dealloc(p_instance); 1138 | 1139 | p_cb->state = NRF_DRV_STATE_UNINITIALIZED; 1140 | return NRF_SUCCESS; 1141 | } 1142 | 1143 | 1144 | //lint -restore 1145 | #endif //NRF_MODULE_ENABLED(APP_PWM) 1146 | --------------------------------------------------------------------------------