VTT TinyNode, slightly modified code from example (https://developer.mbed.org/users/jejuho/code/VTT_NODEV3_BMP180_Si7021)
Dependencies: BLE_API TMP_nrf51 mbed nRF51822
Fork of VTT_NODEV3_BMP180_Si7021 by
Revision 0:de3e4a57ebe0, committed 2015-12-08
- Comitter:
- jejuho
- Date:
- Tue Dec 08 11:58:59 2015 +0000
- Child:
- 1:bd7fd35251ab
- Commit message:
- Works OK.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AT45.cpp Tue Dec 08 11:58:59 2015 +0000 @@ -0,0 +1,1014 @@ +/* mbed AT45 Library, for driving the Atmel AT45 series Dataflash with Serial Interface (SPI) + * Copyright (c) 2012, Created by Steen Joergensen (stjo2809) inspired by Chris Styles AT45 library + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "mbed.h" +#include "AT45.h" +#include "nrf_delay.h" + +//============================================================================= +// Public functions +//============================================================================= + +AT45::AT45(SPI& spi, PinName ncs) : _spi(spi), _ncs(ncs) +{ + + _pages = -1; // number of pages + _pagesize = -1; // size of pages 256/264, 512/528, 1024/1056 + _devicesize = -1; // In bytes + _deep_down = true; // variable for deep power down function (awake ?) + _deep_down_onoff = false; // variable for deep power down function (On/Off) + + _initialize(); // Populate all this stuff + +} + +// This function returns the char +char AT45::read_byte(int address) +{ + // return byte from address + return (_memread( address )); +} + +int AT45::read_page(char* data, int page) +{ + int address = -1; + + if(_pagesize == 256) + { + address = page * 256; + } + else if(_pagesize == 264) + { + address = page * 512; + } + else if(_pagesize == 512) + { + address = page * 512; + } + else if(_pagesize == 528) + { + address = page * 1024; + } + else if(_pagesize == 1024) + { + address = page * 1024; + } + else if(_pagesize == 1056) + { + address = page * 2048; + } + else + { + return (-1); // something isnt configured right + } + + _busy(); + _flashread(1,address); // read the first page of the block into SRAM buffer 1 + _busy(); // Wait until First page has loaded into buffer 1 + + // this is done directly as we are reading back an entire buffer, and this can be done more optimally than using _sramread + _select(); + _spi.write(0xd4); + _sendaddr (0x0); + _spi.write (0x0); // dont care byte + + for(int i=0; i<_pagesize ;i++) + { + data[i] = _spi.write (0x0); + } + _deselect(); + + return (0); +} +int AT45::read_block(char *data, int block) // under construction F�R CHECK AF MIC OG LERCHE +{ + char temp_data[_pagesize]; + int page_start; + + if (block < _blocks || block == 0) { + page_start = block * 8; + + for (int i=0; i<8; i++) { + read_page(temp_data, page_start); + //printf("%d Read round, Data is: %d\r\n",i,*temp_data); + page_start = page_start + 1; + for (int z=0; z<_pagesize ; z++) { + data[z+(_pagesize*i)] = temp_data[z]; + } + } + } else { + //do nothing + } + //printf("Read done, Data is: %d\r\n",*data); + return (0); +} + +int AT45::read_block(char *data[], int block) // under construction F� CHECK AF MIC OG LERCHE +{ + char temp_data[_pagesize]; + int page_start; + + if(block < _blocks || block == 0) + { + page_start = block * 8; + + for(int i=0; i<8 ;i++) // 8 pages in a block + { + read_page(temp_data, page_start); + page_start = page_start + 1; + for(int z=0; z<_pagesize ;z++) + { + data[i][z] = temp_data[z]; + } + } + } + else + { + //do nothing + } + + return (0); +} + +// This function writes the char to the address supplied +// Note : We pass the raw address to the underlying functions +void AT45::write_byte(int address, char data) +{ + _busy(); + _flashread(1,address); // read the Flash page into SRAM buffer + _busy(); // wait for the read to complete + _sramwrite(1,address,data); // Write new data into SRAM + _busy(); // Make sure flash isnt busy + _flashwrite(1,address); // Write back to the page address +} + +int AT45::write_page(char* data, int page) +{ + int address = -1; + + if(_pagesize == 256) + { + address = page * 256; + } + else if(_pagesize == 264) + { + address = page * 512; + } + else if(_pagesize == 512) + { + address = page * 512; + } + else if(_pagesize == 528) + { + address = page * 1024; + } + else if(_pagesize == 1024) + { + address = page * 1024; + } + else if(_pagesize == 1056) + { + address = page * 2048; + } + else + { + return (-1); // something isnt configured right + } + + _select(); + _spi.write(0x84); // writing to buffer #1 + _sendaddr (0); // we are writing to the entire buffer + + for(int i=0; i<_pagesize ;i++) + { + _spi.write (data[i]); + } + _deselect(); + + _busy(); // make sure the Flahs isnt busy + + // issue command to write buffer 1 to the appropraite flash page + _select(); + _spi.write (0x83); + _sendaddr (_getpaddr(address)); + _deselect(); + + return (0); +} +int AT45::write_block(char *data, int block) // under construction F�R CHECK AF MIC OG LERCHE +{ + + int page_start; + char page_arr[_pagesize]; + + if (block < _blocks || block == 0) + { + page_start = block * 8; + + for (int i=0; i<8 ; i++) + { + // Copy data from *data at 0 to 511 _ 512 - 1023, and so on every round. + memcpy(page_arr, &data[_pagesize*i], _pagesize); + + write_page(page_arr, page_start); + page_start = page_start + 1; + } + } else { + //do nothing + } + + return (0); +} +int AT45::write_block(char *data[], int block) // under construction F� CHECK AF MIC OG LERCHE +{ + char temp_data[_pagesize]; + int page_start; + + if(block < _blocks || block == 0) + { + page_start = block * 8; + + for(int i=0; i<8 ;i++) + { + for(int z=0; z<_pagesize ;z++) + { + temp_data[z] = data[i][z]; + } + write_page(temp_data, page_start); + page_start = page_start + 1; + } + } + else + { + //do nothing + } + + return (0); +} + +int AT45::FAT_read(char* data, int page) +{ + // For 256 byte pages, we read two pages + if((_pagesize == 256) || (_pagesize == 264)) + { + int address = page * 512; // This is the start address of the 512 byte block + + _flashread(1,address); // read the first page of the block into SRAM buffer 1 + _busy(); // Wait until First page has loaded into buffer 1 + + // this is done directly as we are reading back an entire buffer, and this can be done more optimally than using _sramread + _select(); + _spi.write(0xd4); + _sendaddr (0x0); + _spi.write (0x0); // dont care byte + + for(int i=0;i<256;i++) + { + data[i] = _spi.write (0x0); + } + _deselect(); + + _flashread(1,address+256); // read the second page of the block into SRAM buffer 2 + _busy(); // Wait until second page has loaded into buffer 2 + + // Now the second page is loaded, pull this out into the second half of the data buffer + // this is done directly as we are reading back an entire buffer, and this can be done more optimally than using _sramread + _select(); + _spi.write(0xd4); + _sendaddr (0x0); + _spi.write (0x0); // dont care byte + + for(int i=0;i<256;i++) + { + data[256+i] = _spi.write (0x0); + } + _deselect(); + return (0); + } + + // For 512 byte pages, we read just the single page, transfer it + else if((_pagesize == 512) || (_pagesize == 528)) + { + int address = page * 512; // This is the start address of the 512 byte block + + _busy(); // Wait until First page has loaded into buffer 1 + _flashread(1,address); // read the first page of the block into SRAM buffer 1 + _busy(); // Wait until First page has loaded into buffer 1 + + // Now the page has loaded, simply transfer it from the sram buffer to the data array + // this is done directly as we are reading back an entire buffer, and this can be done more optimally than using _sramread + _select(); + _spi.write(0xd4); + _sendaddr (0x0); + _spi.write (0x0); // dont care byte + + for(int i=0;i<512;i++) + { + data[i] = _spi.write (0x0); + } + _deselect(); + return (0); + } + + // For 1024 byte pages, we read just a single page, transfer half of it + else if((_pagesize == 1024) || (_pagesize == 1056)) + { + int address = _getpaddr(page * 512); // This is the start address of the 512 byte block + + _busy(); // Wait until First page has loaded into buffer 1 + + _flashread(1,address); // read the first page of the block into SRAM buffer 1 + + _busy(); // Wait until First page has loaded into buffer 1 + + // Now the page has loaded, simply transfer it from the sram buffer to the data array + // this is done directly as we are reading back an entire buffer, and this can be done more optimally than using _sramread + + _select(); + _spi.write(0xd4); + + if (page %2) // odd numbered block, read from adress 0x200 + { + _sendaddr (0x200); + } + else // even numbered block, then we are reading from sram buffer 0x0 + { + _sendaddr (0x0); + } + + _spi.write (0x0); // dont care byte + + for(int i=0;i<512;i++) + { + data[i] = _spi.write (0x0); + } + _deselect(); + return (0); + } + else + { + return (-1); // something isnt configured right + } +} + +int AT45::FAT_write(char* data, int page) +{ + // For 256 byte pages, we overwrite two pages + if((_pagesize == 256) || (_pagesize == 264)) + { + + // fill the first buffer with the first half of the block + // do this directly, for better performance + _select(); + _spi.write(0x84); // writing to buffer #1 + _sendaddr (0); // we are writing to the entire buffer + + for(int i=0;i<256;i++) { + _spi.write (data[i]); + } + _deselect(); + + _flashwrite(1,(page*512)); + + // fill the buffer with the second half of the block + // do this directly, for better performance + _select(); + _spi.write(0x84); // writing to buffer #1 + _sendaddr (0); // we are writing to the entire buffer + + for(int i=0;i<256;i++) { + _spi.write (data[256+i]); + } + _deselect(); + + _flashwrite(1,((page*512)+256)); + } + + // For 512 byte pages, we overwrite a single page + else if((_pagesize == 512) || (_pagesize == 528)) + { + + // fill the first buffer with the block data + // do this directly, for better performance + _select(); + _spi.write(0x84); // writing to buffer #1 + _sendaddr (0); // we are writing to the entire buffer + + for(int i=0;i<512;i++) { + _spi.write (data[i]); + } + _deselect(); + + _busy(); // make sure the Flahs isnt busy + + // issue command to write buffer 1 to the appropraite flash page + _select(); + _spi.write (0x83); + _sendaddr (_getpaddr(page * 512)); + _deselect(); + } + + // For 1024 byte pages, we do a read modify write + // must make sure we overwrite the right half of the page! + else if((_pagesize == 1024) || (_pagesize == 1056)) + { + + _busy(); // make sure the flash isnt busy + + int address = _getpaddr(page*512); + + // Read the page into sram + _flashread(1,address); + + // wait for this operation to complete + _busy(); + + // Overwrite the appropriate half + // do this directly, for better performance + _select(); + _spi.write(0x84); // writing to buffer #1 + + if(page%2) // this is an odd block number, overwrite second half of buffer + { + _sendaddr (0x200); // we are writing to the entire buffer + } + else // this is an even block, overwrite the first half + { + _sendaddr (0x0); // we are writing to the entire buffer + } + + for(int i=0;i<512;i++) + { + _spi.write (data[i]); + } + _deselect(); + + // Write the page back + _busy(); + _flashwrite(1,address); + } + + // Something has gone wrong + else + { + return (-1); + } + + return (0); +} + +// Erase the entire chip +void AT45::chip_erase() +{ + _busy(); // make sure flash isnt already in busy. + + _select(); + // 4 byte command sequence + _spi.write(0xc7); + _spi.write(0x94); + _spi.write(0x80); + _spi.write(0x9a); + _deselect(); + + _busy(); // Make erase a blocking function +} + +// Erase one block +void AT45::block_erase(int block) +{ + int address = -1; + + // Calculate page addresses + if(block < _blocks || block == 0) + { + if(_pagesize == 256) + { + address = block * 2048; + } + else if(_pagesize == 264) + { + address = block * 4096; + } + else if(_pagesize == 512) + { + address = block * 4096; + } + else if(_pagesize == 528) + { + address = block * 8192; + } + else if(_pagesize == 1024) + { + address = block * 8192; + } + else if(_pagesize == 1056) + { + address = block * 16384; + } + + _busy(); + _select(); + _spi.write(0x50); + _sendaddr (address); + _deselect(); + _busy(); + } + else + { + //do nothing + } +} + +// Erase one page +void AT45::page_erase(int page) +{ + int address = -1; + + // Calculate page addresses + if(page < _pages || page == 0) + { + if(_pagesize == 256) + { + address = page * 256; + } + else if(_pagesize == 264) + { + address = page * 512; + } + else if(_pagesize == 512) + { + address = page * 512; + } + else if(_pagesize == 528) + { + address = page * 1024; + } + else if(_pagesize == 1024) + { + address = page * 1024; + } + else if(_pagesize == 1056) + { + address = page * 2048; + } + + _busy(); + _select(); + _spi.write(0x81); + _sendaddr (address); + _deselect(); + _busy(); + } + else + { + //do nothing + } +} + +// return the size of the part in bytes +int AT45::device_size() +{ + return _devicesize; +} + +// return the numbers of pages +int AT45::pages() +{ + return _pages; +} + +// return the page size of the part in bytes +int AT45::pagesize() +{ + return _pagesize; +} + +// A one-time programmable configuration +void AT45::set_pageszie_to_binary() +{ + _busy(); // make sure flash isnt already in busy. + + _select(); + // 4 byte command sequence + _spi.write(0x3d); + _spi.write(0x2a); + _spi.write(0x80); + _spi.write(0xa6); + _deselect(); + + _busy(); // Make erase a blocking function +} + +// Return the number of blocks in this device in accordance with the datasheet +int AT45::blocks() +{ + return _blocks; +} + +// Return the Id of the part +int AT45::id() +{ + int id = 0; + _select(); + _spi.write(0x9f); + id = (_spi.write(0x00) << 8); + id |= _spi.write(0x00); + _deselect(); + return id; +} + +// return the Status +int AT45::status() +{ + int status = 0; + _select(); + _spi.write(0xd7); + status = (_spi.write(0x00)); + _deselect(); + return status; +} + +// Make sure the Flash isnt already doing something +void AT45::busy() +{ + _busy(); +} + +void AT45::deep_power_down(bool _deep_down_onoff) +{ + if(_deep_down_onoff == false) // Wake up from deep power down + { + _select(); + _spi.write(0xab); + _deselect(); + _deep_down = true; + // remenber to want 35uS before using the device. + } + else if(_deep_down_onoff == true) // Go to deep power down + { + _busy(); + _select(); + _spi.write(0xb9); + _deselect(); + _deep_down = false; + } + else + { + //do nothing + } +} + +void AT45::ultra_deep_power_down(bool _deep_down_onoff) +{ + if(_deep_down_onoff == false) // Wake up from deep power down + { + _select(); + //_spi.write(0xab); + //wait 20ns + nrf_delay_us(1); + _deselect(); + _deep_down = true; + // remenber to want 35uS before using the device. + } + else if(_deep_down_onoff == true) // Go to deep power down + { + _busy(); + _select(); + _spi.write(0x79); + _deselect(); + _deep_down = false; + } + else + { + //do nothing + } +} + +bool AT45::is_it_awake() +{ + return _deep_down; +} + +//============================================================================= +// Private functions +//============================================================================= + +void AT45::_initialize() +{ + int _id = 0; + int _status = 0; + + _id = id(); + _id = id(); + _status = status(); + + if ((_id & 0x1f) == 0x3) // 2Mbits + { + _devicesize = 262144; // Size in bytes + _pages = 1024; // Number of pages + _blocks = 128; // Number of blocks + if (_status & 0x1) + { + _pagesize = 256; + } + else + { + _pagesize = 264; + } + } + else if ( (_id & 0x1f) == 0x4) // 4Mbits + { + _devicesize = 524288; + _pages = 2048; + _blocks = 256; + if (_status & 0x1) + { + _pagesize = 256; + } + else + { + _pagesize = 264; + } + } + else if ( (_id & 0x1f) == 0x5) // 8Mbits + { + _devicesize = 1048576; + _pages = 4096; + _blocks = 512; + if (_status & 0x1) + { + _pagesize = 256; + } + else + { + _pagesize = 264; + } + } + else if ( (_id & 0x1f) == 0x6) // 16Mbits + { + _devicesize = 2097152; + _pages = 4096; + _blocks = 512; + if (_status & 0x1) + { + _pagesize = 512; + } + else + { + _pagesize = 528; + } + } + else if ( (_id & 0x1f) == 0x7) // 32Mbits + { + _devicesize = 4194304; + _pages = 8192; + _blocks = 1024; + if (_status & 0x1) + { + _pagesize = 512; + } + else + { + _pagesize = 528; + } + } + else if ( (_id & 0x1f) == 0x8) // 64Mbits + { + _devicesize = 8388608; + _pages = 8192; + _blocks = 1024; + if (_status & 0x1) + { + _pagesize = 1024; + } + else + { + _pagesize = 1056; + } + } + else + { + _devicesize = -1; + _pages = -1; + _pagesize = -1; + _blocks = -1; + } +} + +void AT45::_select() +{ + _ncs = 0; +} + +void AT45::_deselect() +{ + _ncs = 1; +} + +void AT45::_busy() { + volatile int iambusy = 1; + while (iambusy) { + // if bit 7 is set, we can proceed + if ( status() & 0x80 ) { + iambusy = 0;} + } +} + +// Write to an SRAM buffer +// Note : We create buffer and page addresses in _sram and _flash +void AT45::_sramwrite(int buffer, int address, int data) +{ + + int cmd = 0; + int baddr = 0; + + baddr = _getbaddr(address); + + _busy(); + + _select(); + + if (buffer == 1) + {cmd = 0x84;} + else + {cmd = 0x87;} + + _spi.write(cmd); + _sendaddr (baddr); + _spi.write (data); + + _deselect(); +} + +// Read from an SRAM buffer +// Note : We create buffer and page addresses in _sram and _flash +int AT45::_sramread(int buffer, int address) +{ + + int cmd = 0; + int baddr = 0; + int bufdata = 0; + + baddr = _getbaddr(address); + + _select(); + + if(buffer == 1) + {cmd = 0xd4;} + else + {cmd = 0xd6;} + + _spi.write(cmd); + _sendaddr (baddr); + _spi.write (0x0); // dont care byte + bufdata = _spi.write (0x0); + + _deselect(); + + return (bufdata); +} + +// Write and SRAM buffer to main memory +void AT45::_flashwrite (int buffer, int address) +{ + + int cmd = 0; + int paddr = _getpaddr(address); + + _busy(); // Check flash is not busy + + _select(); + + if (buffer == 1) + {cmd = 0x83;} + else + {cmd = 0x86;} + + _spi.write (cmd); + _sendaddr (paddr); + _deselect(); + + _busy(); // Check flash is not busy +} + +// Read from Flash memory into SRAM buffer +void AT45::_flashread (int buffer, int address) +{ + + int cmd = 0; + int paddr = _getpaddr(address); // calculate page address + + _busy(); // Check flash is not busy + _select(); + + if (buffer == 1) + {cmd = 0x53;} + else + {cmd = 0x55;} + + _spi.write (cmd); + _sendaddr (paddr); + _deselect(); +} + +// Read directly from main memory +int AT45::_memread (int address) +{ + + int data = 0; + int addr; + + addr = _getpaddr(address) | _getbaddr(address); + + _busy(); + + _select(); + + _spi.write (0xd2); // Direct read command + _sendaddr (addr); + + // 4 dont care bytes + _spi.write (0x00); + _spi.write (0x00); + _spi.write (0x00); + _spi.write (0x00); + + // this one clocks the data + data = _spi.write (0x00); + _deselect(); + + _busy(); + + return data; +} + +// Work out the page address +// If we have a 2^N page size, it is just the top N bits +// If we have non-2^N, we use the shifted address +int AT45::_getpaddr(int address) +{ + + int paddr; + + if (_pagesize == 256) { + paddr = address & 0xffffff00;} + else if (_pagesize == 264) { + paddr = (address << 1) & 0xfffffe00;} + else if (_pagesize == 512) { + paddr = address & 0xfffffe00;} + else if (_pagesize == 528 ) { + paddr = (address << 1) & 0xfffffc00;} + else if (_pagesize == 1024) { + paddr = address & 0xfffffc00;} + else if (_pagesize == 1056 ) { + paddr = (address << 1) & 0xfffff800;} + else { + paddr = -1;} + + return (paddr); +} + +// Clean the buffer address. This is the 8/9/10 LSBs +int AT45::_getbaddr(int address) +{ + + int baddr; + + if ((_pagesize == 256) || (_pagesize == 264 )) { + baddr = address & 0xff;} + else if ((_pagesize == 512) || (_pagesize == 528 )) { + baddr = address & 0x1ff;} + else if ((_pagesize == 1024) || (_pagesize == 1056 )) { + baddr = address & 0x3ff;} + else { + baddr = -1;} + + return (baddr); +} + +// Sends the three lest significant bytes of the supplied address +void AT45::_sendaddr (int address) +{ + _spi.write(address >> 16); + _spi.write(address >> 8); + _spi.write(address); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AT45.h Tue Dec 08 11:58:59 2015 +0000 @@ -0,0 +1,280 @@ +/* mbed AT45 Library, for driving the Atmel AT45 series Dataflash with Serial Interface (SPI) + * Copyright (c) 2012, Created by Steen Joergensen (stjo2809) inspired by Chris Styles AT45 library + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * + * This driver supports 021,041,081,161,321,641 variants of the AT45DBxxx family + * + * || Code || Density || Page size || Pages || Package || + * || 021 || 2 || 256 || 1024 || 8 SOIC || + * || 041 || 4 || 256 || 2048 || 8 SOIC || + * || 081 || 8 || 256 || 4096 || 8 SOIC || + * || 161 || 16 || 512 || 4096 || 8 SOIC || + * || 321 || 32 || 512 || 8192 || 8 SOIC || + * || 641 || 64 || 1024 || 8192 || 28 TSOP || + */ + +#include "mbed.h" + +#ifndef AT45_H +#define AT45_H + +//============================================================================= +// Functions Declaration +//============================================================================= + +/** Interface to the Atmel AT45 series Dataflash with Serial Interface (SPI) + * + * Using the driver: + * - remenber to setup SPI in main routine. + * - remenber to setup Chipselect in main routine. + * - remenber to use FAT functions set pagesize to binary. + * + * Limitations of using this driver: + * - can't use lockdown functions. + * - can't use protections functions. + * - can't use security functions. + * + */ +class AT45 { +public: + /** Create an instance of the AT45 connected to specfied SPI pins, with the specified address. + * + * @param spi The mbed SPI instance (make in main routine) + * @param nCs The SPI chip select pin. + */ + AT45(SPI& spi, PinName ncs); + + void initialize() { _initialize(); } + + /** Read a byte. + * + * @param address The address of the byte to read. + * @return The data in the byte. + */ + char read_byte(int address); + + /** Read a page. + * + * @param data The data is pointer to a userdefined array that the page is read into. + * @param page The page number of the page to read (0 to device page size). + * @return Returns "0" or "-1" for error. + */ + int read_page(char* data, int page); + + /** Read a block (from 1 dimension array). + * + * @param data The data is pointer to a userdefined array that holds 4096 bytes of the data that is read into. + * @param block The block number of the block to read (0 to device block size). + * @return Returns "0" or "-1" for error. + */ + int read_block(char *data, int block); + + /** Read a block (from 2 dimension array). + * + * Then using 2 dimension array, the array shall have a starting point like "read_block(data[0],0)" + * @param data The data is pointer to a userdefined array that holds 8 x 512 bytes of the data that is read into. + * @param block The block number of the block to read (0 to device block size). + * @return Returns "0" or "-1" for error. + */ + int read_block(char *data[], int block); + + /** Write a byte. + * + * @param address The address to where the data is storage in the flash. + * @param data The data to write into the flash. + */ + void write_byte(int address, char data); + + /** Write a page. + * + * @param data The data is pointer to a userdefined array that holds the data to write into. + * @param page The page number of the page to write into (0 to device page size). + * @return Returns "0" or "-1" for error. + */ + int write_page(char* data, int page); + + /** Write a block (from 1 dimension array). + * + * @param data The data is pointer to a userdefined array that holds 4096 bytes of the data to write into. + * @param block The block number of the block to write into (0 to device block size). + * @return Returns "0" or "-1" for error. + */ + int write_block(char *data, int block); + + /** Write a block (from 2 dimension array). + * + * Then using 2 dimension array, the array shall have a starting point like "write_block(data[0],0)" + * @param data The data is pointer to a userdefined array that holds 8 x 512 bytes of the data to write into (remenber it has to be a 2 dimension array). + * @param block The block number of the block to write into (0 to device block size). + * @return Returns "0" or "-1" for error. + */ + int write_block(char *data[], int block); + + /** FAT Read (512 bits). + * + * Remenber to set page size to binary. + * @param data The data is pointer to a userdefined array that the page is read into. + * @param page The page number of the page to read (0 to device page size). + * @return Returns "0". + */ + int FAT_read(char* data, int page); + + /** FAT Write (512bits). + * + * Remenber to set page size to binary. + * @param data The data is pointer to a userdefined array that holds the data to write into. + * @param page The page number of the page to write into (0 to device page size). + * @return Returns "0" or "-1" for error. + */ + int FAT_write(char* data, int page); + + /** Function to erase the entire chip. + * + * Issue: + * In a certain percentage of units, the chip erase feature may not function correctly and may adversely affect device operation. + * Therefore, it is recommended that the chip erase commands (opcodes C7H, 94H, 80H, and 9AH) not be used. + * Workaround: + * Use block erase (opcode 50H) as an alternative. The block erase function is not affected by the chip erase issue. + * Resolution: + * The chip erase feature may be fixed with a new revision of the device. Please contact Atmel for the estimated availability of + * devices with the fix. + */ + void chip_erase(void); + + /** Function to erase the selected block. + * + * @param block The selected block to erase. + */ + void block_erase(int block); + + /** Function to erase the selected block. + * + * @param page The number of the page to erase. + */ + void page_erase(int page); + + /** Device size in mbits. + * + * @return device size. + */ + int device_size(void); + + /** Pages in flash. + * + * @return Numbers af pages. + */ + int pages(void); + + /** Page size. + * + * for 2-8 Mbits 256 or 264 + * for 16-32 Mbits 512 or 528 + * for 64 Mbits 1024 or 1056 + * + * @return Page size. + */ + int pagesize(void); + + /** Function to set the page size to binary. + * + * Remenber is a one-time programmable configuration. + * Remenber to total power down after the functions has been run. + */ + void set_pageszie_to_binary(void); + + /** blocks in flash. + * + * @return Numbers af blocks. + */ + int blocks(void); + + /** ID of the device. + * + * @return Manufacturer, Family and Density code. + */ + int id(void); + + /** Status register. + * + * @return The status register. + */ + int status(void); // Status register + + /** busy ?. + * + * Function will want to the device is not busy. + */ + void busy(void); // Wait until Flash is not busy + + /** Deep Power Down. + * + * Remenber that you have to want 35uS after the wake up to use the device. + * @param True = Activate and False = Wake Up. + */ + void deep_power_down(bool onoff); + void ultra_deep_power_down(bool onoff); + + /** Is the device deep power down. + * + * @return True = Activate and False = Awake. + */ + bool is_it_awake(void); + +private: + + SPI _spi; + DigitalOut _ncs; + + int _pages; // Integer number of pages + int _pagesize; // page size, in bytes + int _devicesize; // device size in bytes + int _blocks; // Number of blocks + bool _deep_down; // True = the device is deep down + bool _deep_down_onoff; // variable for deep power down function (On/Off) + + // Helper routunes + void _initialize(); + void _select(); + void _deselect(); + void _busy (void); + + // accessing SRAM buffers + void _sramwrite (int buffer, int address, int data); + int _sramread (int buffer, int address); + + // Transferring SRAM buffers to/from FLASH + void _flashwrite (int buffer, int paddr); + void _flashread (int buffer, int paddr); + + // Reading FLASH directly + int _memread (int address); + + // Calculate page/subpage addresses + int _getpaddr (int); + int _getbaddr (int); + + // Send 3 byte address + void _sendaddr (int address); + +}; +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BLE_API.lib Tue Dec 08 11:58:59 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#1a37289c954e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LEDService.h Tue Dec 08 11:58:59 2015 +0000 @@ -0,0 +1,42 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BLE_LED_SERVICE_H__ +#define __BLE_LED_SERVICE_H__ + +class LEDService { +public: + const static uint16_t LED_SERVICE_UUID = 0xA000; + const static uint16_t LED_STATE_CHARACTERISTIC_UUID = 0xA001; + + LEDService(BLEDevice &_ble, bool initialValueForLEDCharacteristic) : + ble(_ble), ledState(LED_STATE_CHARACTERISTIC_UUID, &initialValueForLEDCharacteristic) + { + GattCharacteristic *charTable[] = {&ledState}; + GattService ledService(LED_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); + ble.addService(ledService); + } + + GattAttribute::Handle_t getValueHandle() const { + return ledState.getValueHandle(); + } + +private: + BLEDevice &ble; + ReadWriteGattCharacteristic<bool> ledState; +}; + +#endif /* #ifndef __BLE_LED_SERVICE_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LIS3DH.cpp Tue Dec 08 11:58:59 2015 +0000 @@ -0,0 +1,1614 @@ +#include "LIS3DH.h" + +LIS3DH::LIS3DH(PinName mosi, PinName miso, PinName ss, PinName sck): _spi(mosi,miso,sck), _ss(ss){ + // Make sure CS is high + _ss = 1; + // Setup the spi for 8 bit data, high steady state clock, + // second edge capture, with a 1MHz clock rate + _spi.format(8,3); + _spi.frequency(8000000); + + +} + +u8_t LIS3DH::InitLIS3DH(LIS3DH_Mode_t Mode, LIS3DH_ODR_t Odr, LIS3DH_Fullscale_t Grange) +{ + uint8_t response; + uint8_t Tmp; + + LIS3DH_GetWHO_AM_I(&Tmp); + + response = LIS3DH_SetODR(Odr); + + //set PowerMode + response = LIS3DH_SetMode(Mode); + + //set Fullscale + response = LIS3DH_SetFullScale(Grange); + + //set axis Enable + response = LIS3DH_SetAxis(LIS3DH_X_ENABLE | LIS3DH_Y_ENABLE | LIS3DH_Z_ENABLE); + + return response; +} + +/******************************************************************************* +* Function Name : LIS3DH_GetStatusAUX +* Description : Read the AUX status register +* Input : Char to empty by status register buffer +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetStatusAUX(u8_t* val) { + + if( !LIS3DH_ReadReg(LIS3DH_STATUS_AUX, val) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_GetStatusAUXBIT +* Description : Read the AUX status register BIT +* Input : LIS3DH_STATUS_AUX_321OR, LIS3DH_STATUS_AUX_3OR, LIS3DH_STATUS_AUX_2OR, LIS3DH_STATUS_AUX_1OR, + LIS3DH_STATUS_AUX_321DA, LIS3DH_STATUS_AUX_3DA, LIS3DH_STATUS_AUX_2DA, LIS3DH_STATUS_AUX_1DA +* Output : None +* Return : Status of BIT [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetStatusAUXBit(u8_t statusBIT, u8_t* val) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_STATUS_AUX, &value) ) + return MEMS_ERROR; + + if(statusBIT == LIS3DH_STATUS_AUX_321OR){ + if(value &= LIS3DH_STATUS_AUX_321OR){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_STATUS_AUX_3OR){ + if(value &= LIS3DH_STATUS_AUX_3OR){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_STATUS_AUX_2OR){ + if(value &= LIS3DH_STATUS_AUX_2OR){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_STATUS_AUX_1OR){ + if(value &= LIS3DH_STATUS_AUX_1OR){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_STATUS_AUX_321DA){ + if(value &= LIS3DH_STATUS_AUX_321DA) { + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_STATUS_AUX_3DA){ + if(value &= LIS3DH_STATUS_AUX_3DA){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_STATUS_AUX_2DA){ + if(value &= LIS3DH_STATUS_AUX_2DA){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_STATUS_AUX_1DA){ + if(value &= LIS3DH_STATUS_AUX_1DA){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + return MEMS_ERROR; +} + +u8_t LIS3DH::SetLIS3DHActivityDetection(uint8_t Th, LIS3DH_Int1Mode_t Mode, uint8_t OnOff) +{ + uint8_t response; + + response = LIS3DH_SetInt1Pin(LIS3DH_CLICK_ON_PIN_INT1_DISABLE | LIS3DH_I1_INT1_ON_PIN_INT1_ENABLE | + LIS3DH_I1_INT2_ON_PIN_INT1_DISABLE | LIS3DH_I1_DRDY1_ON_INT1_DISABLE | LIS3DH_I1_DRDY2_ON_INT1_DISABLE | + LIS3DH_WTM_ON_INT1_DISABLE | LIS3DH_INT1_OVERRUN_DISABLE ); + + //set Interrupt Threshold + response = LIS3DH_SetInt1Threshold(Th); + + //set Interrupt configuration (all enabled) + if(OnOff) + { + response = LIS3DH_SetIntConfiguration(LIS3DH_INT1_ZHIE_ENABLE | LIS3DH_INT1_ZLIE_ENABLE | + LIS3DH_INT1_YHIE_ENABLE | LIS3DH_INT1_YLIE_ENABLE | + LIS3DH_INT1_XHIE_ENABLE | LIS3DH_INT1_XLIE_ENABLE ); + } + else + { + response = LIS3DH_SetIntConfiguration(LIS3DH_INT1_ZHIE_DISABLE | LIS3DH_INT1_ZLIE_DISABLE | + LIS3DH_INT1_YHIE_DISABLE | LIS3DH_INT1_YLIE_DISABLE | + LIS3DH_INT1_XHIE_DISABLE | LIS3DH_INT1_XLIE_DISABLE ); + } + + //set Interrupt Mode + response = LIS3DH_SetIntMode(Mode); + + return response; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetODR +* Description : Sets LIS3DH Output Data Rate +* Input : Output Data Rate +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetODR(LIS3DH_ODR_t ov){ + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG1, &value) ) + return MEMS_ERROR; + + value &= 0x0f; + value |= ov<<LIS3DH_ODR_BIT; + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG1, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetMode +* Description : Sets LIS3DH Operating Mode +* Input : Modality (LIS3DH_NORMAL, LIS3DH_LOW_POWER, LIS3DH_POWER_DOWN) +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetMode(LIS3DH_Mode_t md) { + u8_t value; + u8_t value2; + static u8_t ODR_old_value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG1, &value) ) + return MEMS_ERROR; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG4, &value2) ) + return MEMS_ERROR; + + if((value & 0xF0)==0) + value = value | (ODR_old_value & 0xF0); //if it comes from POWERDOWN + + switch(md) { + + case LIS3DH_POWER_DOWN: + ODR_old_value = value; + value &= 0x0F; + break; + + case LIS3DH_NORMAL: + value &= 0xF7; + value |= (MEMS_RESET<<LIS3DH_LPEN); + value2 &= 0xF7; + value2 |= (MEMS_SET<<LIS3DH_HR); //set HighResolution_BIT + break; + + case LIS3DH_LOW_POWER: + value &= 0xF7; + value |= (MEMS_SET<<LIS3DH_LPEN); + value2 &= 0xF7; + value2 |= (MEMS_RESET<<LIS3DH_HR); //reset HighResolution_BIT + break; + + default: + return MEMS_ERROR; + } + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG1, value) ) + return MEMS_ERROR; + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG4, value2) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetAxis +* Description : Enable/Disable LIS3DH Axis +* Input : LIS3DH_X_ENABLE/DISABLE | LIS3DH_Y_ENABLE/DISABLE | LIS3DH_Z_ENABLE/DISABLE +* Output : None +* Note : You MUST use all input variable in the argument, as example +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetAxis(LIS3DH_Axis_t axis) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG1, &value) ) + return MEMS_ERROR; + value &= 0xF8; + value |= (0x07 & axis); + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG1, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetFullScale +* Description : Sets the LIS3DH FullScale +* Input : LIS3DH_FULLSCALE_2/LIS3DH_FULLSCALE_4/LIS3DH_FULLSCALE_8/LIS3DH_FULLSCALE_16 +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetFullScale(LIS3DH_Fullscale_t fs) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG4, &value) ) + return MEMS_ERROR; + + value &= 0xCF; + value |= (fs<<LIS3DH_FS); + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG4, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetBDU +* Description : Enable/Disable Block Data Update Functionality +* Input : ENABLE/DISABLE +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetBDU(State_t bdu) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG4, &value) ) + return MEMS_ERROR; + + value &= 0x7F; + value |= (bdu<<LIS3DH_BDU); + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG4, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetBLE +* Description : Set Endianess (MSB/LSB) +* Input : BLE_LSB / BLE_MSB +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetBLE(LIS3DH_Endianess_t ble) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG4, &value) ) + return MEMS_ERROR; + + value &= 0xBF; + value |= (ble<<LIS3DH_BLE); + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG4, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetSelfTest +* Description : Set Self Test Modality +* Input : LIS3DH_SELF_TEST_DISABLE/ST_0/ST_1 +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetSelfTest(LIS3DH_SelfTest_t st) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG4, &value) ) + return MEMS_ERROR; + + value &= 0xF9; + value |= (st<<LIS3DH_ST); + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG4, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_HPFClick +* Description : Enable/Disable High Pass Filter for click +* Input : MEMS_ENABLE/MEMS_DISABLE +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_HPFClickEnable(State_t hpfe) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG2, &value) ) + return MEMS_ERROR; + + value &= 0xFB; + value |= (hpfe<<LIS3DH_HPCLICK); + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG2, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_HPFAOI1 +* Description : Enable/Disable High Pass Filter for AOI on INT_1 +* Input : MEMS_ENABLE/MEMS_DISABLE +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_HPFAOI1Enable(State_t hpfe) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG2, &value) ) + return MEMS_ERROR; + + value &= 0xFE; + value |= (hpfe<<LIS3DH_HPIS1); + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG2, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_HPFAOI2 +* Description : Enable/Disable High Pass Filter for AOI on INT_2 +* Input : MEMS_ENABLE/MEMS_DISABLE +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_HPFAOI2Enable(State_t hpfe) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG2, &value) ) + return MEMS_ERROR; + + value &= 0xFD; + value |= (hpfe<<LIS3DH_HPIS2); + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG2, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetHPFMode +* Description : Set High Pass Filter Modality +* Input : LIS3DH_HPM_NORMAL_MODE_RES/LIS3DH_HPM_REF_SIGNAL/ + LIS3DH_HPM_NORMAL_MODE/LIS3DH_HPM_AUTORESET_INT +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetHPFMode(LIS3DH_HPFMode_t hpm) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG2, &value) ) + return MEMS_ERROR; + + value &= 0x3F; + value |= (hpm<<LIS3DH_HPM); + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG2, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_SetHPFCutOFF +* Description : Set High Pass CUT OFF Freq +* Input : HPFCF [0,3] +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetHPFCutOFF(LIS3DH_HPFCutOffFreq_t hpf) { + u8_t value; + + if (hpf > 3) + return MEMS_ERROR; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG2, &value) ) + return MEMS_ERROR; + + value &= 0xCF; + value |= (hpf<<LIS3DH_HPCF); + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG2, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; + +} + +/******************************************************************************* +* Function Name : LIS3DH_SetFilterDataSel +* Description : Set Filter Data Selection bypassed or sent to FIFO OUT register +* Input : MEMS_SET, MEMS_RESET +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetFilterDataSel(State_t state) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG2, &value) ) + return MEMS_ERROR; + + value &= 0xF7; + value |= (state<<LIS3DH_FDS); + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG2, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; + +} + +/******************************************************************************* +* Function Name : LIS3DH_SetTemperature +* Description : Sets LIS3DH Output Temperature +* Input : MEMS_ENABLE, MEMS_DISABLE +* Output : None +* Note : For Read Temperature by LIS3DH_OUT_AUX_3, LIS3DH_SetADCAux and LIS3DH_SetBDU + functions must be ENABLE +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetTemperature(State_t state){ + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_TEMP_CFG_REG, &value) ) + return MEMS_ERROR; + + value &= 0xBF; + value |= state<<LIS3DH_TEMP_EN; + + if( !LIS3DH_WriteReg(LIS3DH_TEMP_CFG_REG, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetADCAux +* Description : Sets LIS3DH Output ADC +* Input : MEMS_ENABLE, MEMS_DISABLE +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetADCAux(State_t state){ + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_TEMP_CFG_REG, &value) ) + return MEMS_ERROR; + + value &= 0x7F; + value |= state<<LIS3DH_ADC_PD; + + if( !LIS3DH_WriteReg(LIS3DH_TEMP_CFG_REG, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_GetAuxRaw +* Description : Read the Aux Values Output Registers +* Input : Buffer to empty +* Output : Aux Values Registers buffer +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetAuxRaw(LIS3DH_Aux123Raw_t* buff) { + u8_t valueL; + u8_t valueH; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_1_L, &valueL) ) + return MEMS_ERROR; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_1_H, &valueH) ) + return MEMS_ERROR; + + buff->AUX_1 = (u16_t)( (valueH << 8) | valueL )/16; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_2_L, &valueL) ) + return MEMS_ERROR; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_2_H, &valueH) ) + return MEMS_ERROR; + + buff->AUX_2 = (u16_t)( (valueH << 8) | valueL )/16; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_3_L, &valueL) ) + return MEMS_ERROR; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_3_H, &valueH) ) + return MEMS_ERROR; + + buff->AUX_3 = (u16_t)( (valueH << 8) | valueL )/16; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetInt1Pin +* Description : Set Interrupt1 pin Function +* Input : LIS3DH_CLICK_ON_PIN_INT1_ENABLE/DISABLE | LIS3DH_I1_INT1_ON_PIN_INT1_ENABLE/DISABLE | + LIS3DH_I1_INT2_ON_PIN_INT1_ENABLE/DISABLE | LIS3DH_I1_DRDY1_ON_INT1_ENABLE/DISABLE | + LIS3DH_I1_DRDY2_ON_INT1_ENABLE/DISABLE | LIS3DH_WTM_ON_INT1_ENABLE/DISABLE | + LIS3DH_INT1_OVERRUN_ENABLE/DISABLE +* example : SetInt1Pin(LIS3DH_CLICK_ON_PIN_INT1_ENABLE | LIS3DH_I1_INT1_ON_PIN_INT1_ENABLE | + LIS3DH_I1_INT2_ON_PIN_INT1_DISABLE | LIS3DH_I1_DRDY1_ON_INT1_ENABLE | LIS3DH_I1_DRDY2_ON_INT1_ENABLE | + LIS3DH_WTM_ON_INT1_DISABLE | LIS3DH_INT1_OVERRUN_DISABLE ) +* Note : To enable Interrupt signals on INT1 Pad (You MUST use all input variable in the argument, as example) +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetInt1Pin(LIS3DH_IntPinConf_t pinConf) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG3, &value) ) + return MEMS_ERROR; + + value &= 0x00; + value |= pinConf; + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG3, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_SetInt2Pin +* Description : Set Interrupt2 pin Function +* Input : LIS3DH_CLICK_ON_PIN_INT2_ENABLE/DISABLE | LIS3DH_I2_INT1_ON_PIN_INT2_ENABLE/DISABLE | + LIS3DH_I2_INT2_ON_PIN_INT2_ENABLE/DISABLE | LIS3DH_I2_BOOT_ON_INT2_ENABLE/DISABLE | + LIS3DH_INT_ACTIVE_HIGH/LOW +* example : LIS3DH_SetInt2Pin(LIS3DH_CLICK_ON_PIN_INT2_ENABLE/DISABLE | LIS3DH_I2_INT1_ON_PIN_INT2_ENABLE/DISABLE | + LIS3DH_I2_INT2_ON_PIN_INT2_ENABLE/DISABLE | LIS3DH_I2_BOOT_ON_INT2_ENABLE/DISABLE | + LIS3DH_INT_ACTIVE_HIGH/LOW) +* Note : To enable Interrupt signals on INT2 Pad (You MUST use all input variable in the argument, as example) +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetInt2Pin(LIS3DH_IntPinConf_t pinConf) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG6, &value) ) + return MEMS_ERROR; + + value &= 0x00; + value |= pinConf; + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG6, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetClickCFG +* Description : Set Click Interrupt config Function +* Input : LIS3DH_ZD_ENABLE/DISABLE | LIS3DH_ZS_ENABLE/DISABLE | LIS3DH_YD_ENABLE/DISABLE | + LIS3DH_YS_ENABLE/DISABLE | LIS3DH_XD_ENABLE/DISABLE | LIS3DH_XS_ENABLE/DISABLE +* example : LIS3DH_SetClickCFG( LIS3DH_ZD_ENABLE | LIS3DH_ZS_DISABLE | LIS3DH_YD_ENABLE | + LIS3DH_YS_DISABLE | LIS3DH_XD_ENABLE | LIS3DH_XS_ENABLE) +* Note : You MUST use all input variable in the argument, as example +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetClickCFG(u8_t status) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CLICK_CFG, &value) ) + return MEMS_ERROR; + + value &= 0xC0; + value |= status; + + if( !LIS3DH_WriteReg(LIS3DH_CLICK_CFG, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_SetClickTHS +* Description : Set Click Interrupt threshold +* Input : Click-click Threshold value [0-127] +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetClickTHS(u8_t ths) { + + if(ths>127) + return MEMS_ERROR; + + if( !LIS3DH_WriteReg(LIS3DH_CLICK_THS, ths) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_SetClickLIMIT +* Description : Set Click Interrupt Time Limit +* Input : Click-click Time Limit value [0-127] +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetClickLIMIT(u8_t t_limit) { + + if(t_limit>127) + return MEMS_ERROR; + + if( !LIS3DH_WriteReg(LIS3DH_TIME_LIMIT, t_limit) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_SetClickLATENCY +* Description : Set Click Interrupt Time Latency +* Input : Click-click Time Latency value [0-255] +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetClickLATENCY(u8_t t_latency) { + + if( !LIS3DH_WriteReg(LIS3DH_TIME_LATENCY, t_latency) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_SetClickWINDOW +* Description : Set Click Interrupt Time Window +* Input : Click-click Time Window value [0-255] +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetClickWINDOW(u8_t t_window) { + + if( !LIS3DH_WriteReg(LIS3DH_TIME_WINDOW, t_window) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_GetClickResponse +* Description : Get Click Interrupt Response by CLICK_SRC REGISTER +* Input : char to empty by Click Response Typedef +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetClickResponse(u8_t* res) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CLICK_SRC, &value) ) + return MEMS_ERROR; + + value &= 0x7F; + + if((value & LIS3DH_IA)==0) { + *res = LIS3DH_NO_CLICK; + return MEMS_SUCCESS; + } + else { + if (value & LIS3DH_DCLICK){ + if (value & LIS3DH_CLICK_SIGN){ + if (value & LIS3DH_CLICK_Z) { + *res = LIS3DH_DCLICK_Z_N; + return MEMS_SUCCESS; + } + if (value & LIS3DH_CLICK_Y) { + *res = LIS3DH_DCLICK_Y_N; + return MEMS_SUCCESS; + } + if (value & LIS3DH_CLICK_X) { + *res = LIS3DH_DCLICK_X_N; + return MEMS_SUCCESS; + } + } + else{ + if (value & LIS3DH_CLICK_Z) { + *res = LIS3DH_DCLICK_Z_P; + return MEMS_SUCCESS; + } + if (value & LIS3DH_CLICK_Y) { + *res = LIS3DH_DCLICK_Y_P; + return MEMS_SUCCESS; + } + if (value & LIS3DH_CLICK_X) { + *res = LIS3DH_DCLICK_X_P; + return MEMS_SUCCESS; + } + } + } + else{ + if (value & LIS3DH_CLICK_SIGN){ + if (value & LIS3DH_CLICK_Z) { + *res = LIS3DH_SCLICK_Z_N; + return MEMS_SUCCESS; + } + if (value & LIS3DH_CLICK_Y) { + *res = LIS3DH_SCLICK_Y_N; + return MEMS_SUCCESS; + } + if (value & LIS3DH_CLICK_X) { + *res = LIS3DH_SCLICK_X_N; + return MEMS_SUCCESS; + } + } + else{ + if (value & LIS3DH_CLICK_Z) { + *res = LIS3DH_SCLICK_Z_P; + return MEMS_SUCCESS; + } + if (value & LIS3DH_CLICK_Y) { + *res = LIS3DH_SCLICK_Y_P; + return MEMS_SUCCESS; + } + if (value & LIS3DH_CLICK_X) { + *res = LIS3DH_SCLICK_X_P; + return MEMS_SUCCESS; + } + } + } + } + return MEMS_ERROR; +} + + +/******************************************************************************* +* Function Name : LIS3DH_Int1LatchEnable +* Description : Enable Interrupt 1 Latching function +* Input : ENABLE/DISABLE +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_Int1LatchEnable(State_t latch) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG5, &value) ) + return MEMS_ERROR; + + value &= 0xF7; + value |= latch<<LIS3DH_LIR_INT1; + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG5, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +status_t LIS3DH::LIS3DH_ResetInt1Latch(void) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_INT1_SRC, &value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetIntConfiguration +* Description : Interrupt 1 Configuration (without LIS3DH_6D_INT) +* Input : LIS3DH_INT1_AND/OR | LIS3DH_INT1_ZHIE_ENABLE/DISABLE | LIS3DH_INT1_ZLIE_ENABLE/DISABLE... +* Output : None +* Note : You MUST use all input variable in the argument, as example +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetIntConfiguration(LIS3DH_Int1Conf_t ic) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_INT1_CFG, &value) ) + return MEMS_ERROR; + + value &= 0x40; + value |= ic; + + if( !LIS3DH_WriteReg(LIS3DH_INT1_CFG, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_SetIntMode +* Description : Interrupt 1 Configuration mode (OR, 6D Movement, AND, 6D Position) +* Input : LIS3DH_INT_MODE_OR, LIS3DH_INT_MODE_6D_MOVEMENT, LIS3DH_INT_MODE_AND, + LIS3DH_INT_MODE_6D_POSITION +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetIntMode(LIS3DH_Int1Mode_t int_mode) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_INT1_CFG, &value) ) + return MEMS_ERROR; + + value &= 0x3F; + value |= (int_mode<<LIS3DH_INT_6D); + + if( !LIS3DH_WriteReg(LIS3DH_INT1_CFG, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetInt6D4DConfiguration +* Description : 6D, 4D Interrupt Configuration +* Input : LIS3DH_INT1_6D_ENABLE, LIS3DH_INT1_4D_ENABLE, LIS3DH_INT1_6D_4D_DISABLE +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetInt6D4DConfiguration(LIS3DH_INT_6D_4D_t ic) { + u8_t value; + u8_t value2; + + if( !LIS3DH_ReadReg(LIS3DH_INT1_CFG, &value) ) + return MEMS_ERROR; + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG5, &value2) ) + return MEMS_ERROR; + + if(ic == LIS3DH_INT1_6D_ENABLE){ + value &= 0xBF; + value |= (MEMS_ENABLE<<LIS3DH_INT_6D); + value2 &= 0xFB; + value2 |= (MEMS_DISABLE<<LIS3DH_D4D_INT1); + } + + if(ic == LIS3DH_INT1_4D_ENABLE){ + value &= 0xBF; + value |= (MEMS_ENABLE<<LIS3DH_INT_6D); + value2 &= 0xFB; + value2 |= (MEMS_ENABLE<<LIS3DH_D4D_INT1); + } + + if(ic == LIS3DH_INT1_6D_4D_DISABLE){ + value &= 0xBF; + value |= (MEMS_DISABLE<<LIS3DH_INT_6D); + value2 &= 0xFB; + value2 |= (MEMS_DISABLE<<LIS3DH_D4D_INT1); + } + + if( !LIS3DH_WriteReg(LIS3DH_INT1_CFG, value) ) + return MEMS_ERROR; + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG5, value2) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_Get6DPosition +* Description : 6D, 4D Interrupt Position Detect +* Input : Byte to empty by POSITION_6D_t Typedef +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_Get6DPosition(u8_t* val){ + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_INT1_SRC, &value) ) + return MEMS_ERROR; + + value &= 0x7F; + + switch (value){ + case LIS3DH_UP_SX: + *val = LIS3DH_UP_SX; + break; + case LIS3DH_UP_DX: + *val = LIS3DH_UP_DX; + break; + case LIS3DH_DW_SX: + *val = LIS3DH_DW_SX; + break; + case LIS3DH_DW_DX: + *val = LIS3DH_DW_DX; + break; + case LIS3DH_TOP: + *val = LIS3DH_TOP; + break; + case LIS3DH_BOTTOM: + *val = LIS3DH_BOTTOM; + break; + } + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetInt1Threshold +* Description : Sets Interrupt 1 Threshold +* Input : Threshold = [0,31] +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetInt1Threshold(u8_t ths) { + if (ths > 127) + return MEMS_ERROR; + + if( !LIS3DH_WriteReg(LIS3DH_INT1_THS, ths) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetInt1Duration +* Description : Sets Interrupt 1 Duration +* Input : Duration value +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetInt1Duration(LIS3DH_Int1Conf_t id) { + + if (id > 127) + return MEMS_ERROR; + + if( !LIS3DH_WriteReg(LIS3DH_INT1_DURATION, id) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_FIFOModeEnable +* Description : Sets Fifo Modality +* Input : LIS3DH_FIFO_DISABLE, LIS3DH_FIFO_BYPASS_MODE, LIS3DH_FIFO_MODE, + LIS3DH_FIFO_STREAM_MODE, LIS3DH_FIFO_TRIGGER_MODE +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_FIFOModeEnable(LIS3DH_FifoMode_t fm) { + u8_t value; + + if(fm == LIS3DH_FIFO_DISABLE) { + if( !LIS3DH_ReadReg(LIS3DH_FIFO_CTRL_REG, &value) ) + return MEMS_ERROR; + + value &= 0x1F; + value |= (LIS3DH_FIFO_BYPASS_MODE<<LIS3DH_FM); + + if( !LIS3DH_WriteReg(LIS3DH_FIFO_CTRL_REG, value) ) //fifo mode bypass + return MEMS_ERROR; + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG5, &value) ) + return MEMS_ERROR; + + value &= 0xBF; + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG5, value) ) //fifo disable + return MEMS_ERROR; + } + + if(fm == LIS3DH_FIFO_BYPASS_MODE) { + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG5, &value) ) + return MEMS_ERROR; + + value &= 0xBF; + value |= MEMS_SET<<LIS3DH_FIFO_EN; + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG5, value) ) //fifo enable + return MEMS_ERROR; + if( !LIS3DH_ReadReg(LIS3DH_FIFO_CTRL_REG, &value) ) + return MEMS_ERROR; + + value &= 0x1f; + value |= (fm<<LIS3DH_FM); //fifo mode configuration + + if( !LIS3DH_WriteReg(LIS3DH_FIFO_CTRL_REG, value) ) + return MEMS_ERROR; + } + + if(fm == LIS3DH_FIFO_MODE) { + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG5, &value) ) + return MEMS_ERROR; + + value &= 0xBF; + value |= MEMS_SET<<LIS3DH_FIFO_EN; + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG5, value) ) //fifo enable + return MEMS_ERROR; + if( !LIS3DH_ReadReg(LIS3DH_FIFO_CTRL_REG, &value) ) + return MEMS_ERROR; + + value &= 0x1f; + value |= (fm<<LIS3DH_FM); //fifo mode configuration + + if( !LIS3DH_WriteReg(LIS3DH_FIFO_CTRL_REG, value) ) + return MEMS_ERROR; + } + + if(fm == LIS3DH_FIFO_STREAM_MODE) { + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG5, &value) ) + return MEMS_ERROR; + + value &= 0xBF; + value |= MEMS_SET<<LIS3DH_FIFO_EN; + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG5, value) ) //fifo enable + return MEMS_ERROR; + if( !LIS3DH_ReadReg(LIS3DH_FIFO_CTRL_REG, &value) ) + return MEMS_ERROR; + + value &= 0x1f; + value |= (fm<<LIS3DH_FM); //fifo mode configuration + + if( !LIS3DH_WriteReg(LIS3DH_FIFO_CTRL_REG, value) ) + return MEMS_ERROR; + } + + if(fm == LIS3DH_FIFO_TRIGGER_MODE) { + if( !LIS3DH_ReadReg(LIS3DH_CTRL_REG5, &value) ) + return MEMS_ERROR; + + value &= 0xBF; + value |= MEMS_SET<<LIS3DH_FIFO_EN; + + if( !LIS3DH_WriteReg(LIS3DH_CTRL_REG5, value) ) //fifo enable + return MEMS_ERROR; + if( !LIS3DH_ReadReg(LIS3DH_FIFO_CTRL_REG, &value) ) + return MEMS_ERROR; + + value &= 0x1f; + value |= (fm<<LIS3DH_FM); //fifo mode configuration + + if( !LIS3DH_WriteReg(LIS3DH_FIFO_CTRL_REG, value) ) + return MEMS_ERROR; + } + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetTriggerInt +* Description : Trigger event liked to trigger signal INT1/INT2 +* Input : LIS3DH_TRIG_INT1/LIS3DH_TRIG_INT2 +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetTriggerInt(LIS3DH_TrigInt_t tr) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_FIFO_CTRL_REG, &value) ) + return MEMS_ERROR; + + value &= 0xDF; + value |= (tr<<LIS3DH_TR); + + if( !LIS3DH_WriteReg(LIS3DH_FIFO_CTRL_REG, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_SetWaterMark +* Description : Sets Watermark Value +* Input : Watermark = [0,31] +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_SetWaterMark(u8_t wtm) { + u8_t value; + + if(wtm > 31) + return MEMS_ERROR; + + if( !LIS3DH_ReadReg(LIS3DH_FIFO_CTRL_REG, &value) ) + return MEMS_ERROR; + + value &= 0xE0; + value |= wtm; + + if( !LIS3DH_WriteReg(LIS3DH_FIFO_CTRL_REG, value) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_GetStatusReg +* Description : Read the status register +* Input : char to empty by Status Reg Value +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetStatusReg(u8_t* val) { + if( !LIS3DH_ReadReg(LIS3DH_STATUS_REG, val) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_GetStatusBIT +* Description : Read the status register BIT +* Input : LIS3DH_STATUS_REG_ZYXOR, LIS3DH_STATUS_REG_ZOR, LIS3DH_STATUS_REG_YOR, LIS3DH_STATUS_REG_XOR, + LIS3DH_STATUS_REG_ZYXDA, LIS3DH_STATUS_REG_ZDA, LIS3DH_STATUS_REG_YDA, LIS3DH_STATUS_REG_XDA, + LIS3DH_DATAREADY_BIT + val: Byte to be filled with the status bit +* Output : status register BIT +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetStatusBit(u8_t statusBIT, u8_t* val) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_STATUS_REG, &value) ) + return MEMS_ERROR; + + switch (statusBIT){ + case LIS3DH_STATUS_REG_ZYXOR: + if(value &= LIS3DH_STATUS_REG_ZYXOR){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + case LIS3DH_STATUS_REG_ZOR: + if(value &= LIS3DH_STATUS_REG_ZOR){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + case LIS3DH_STATUS_REG_YOR: + if(value &= LIS3DH_STATUS_REG_YOR){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + case LIS3DH_STATUS_REG_XOR: + if(value &= LIS3DH_STATUS_REG_XOR){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + case LIS3DH_STATUS_REG_ZYXDA: + if(value &= LIS3DH_STATUS_REG_ZYXDA){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + case LIS3DH_STATUS_REG_ZDA: + if(value &= LIS3DH_STATUS_REG_ZDA){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + case LIS3DH_STATUS_REG_YDA: + if(value &= LIS3DH_STATUS_REG_YDA){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + case LIS3DH_STATUS_REG_XDA: + if(value &= LIS3DH_STATUS_REG_XDA){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + + } + return MEMS_ERROR; +} + +/******************************************************************************* +* Function Name : LIS3DH_GetAccAxesRaw +* Description : Read the Acceleration Values Output Registers +* Input : buffer to empity by AxesRaw_t Typedef +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetAccAxesRaw(AxesRaw_t* buff) { + i16_t value; + u8_t *valueL = (u8_t *)(&value); + u8_t *valueH = ((u8_t *)(&value)+1); + + if( !LIS3DH_ReadReg(LIS3DH_OUT_X_L, valueL) ) + return MEMS_ERROR; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_X_H, valueH) ) + return MEMS_ERROR; + + buff->AXIS_X = value; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_Y_L, valueL) ) + return MEMS_ERROR; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_Y_H, valueH) ) + return MEMS_ERROR; + + buff->AXIS_Y = value; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_Z_L, valueL) ) + return MEMS_ERROR; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_Z_H, valueH) ) + return MEMS_ERROR; + + buff->AXIS_Z = value; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_GetInt1Src +* Description : Reset Interrupt 1 Latching function +* Input : Char to empty by Int1 source value +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetInt1Src(u8_t* val) { + + if( !LIS3DH_ReadReg(LIS3DH_INT1_SRC, val) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_GetInt1SrcBit +* Description : Reset Interrupt 1 Latching function +* Input : statusBIT: LIS3DH_INT_SRC_IA, LIS3DH_INT_SRC_ZH, LIS3DH_INT_SRC_ZL..... +* val: Byte to be filled with the status bit +* Output : None +* Return : Status of BIT [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetInt1SrcBit(u8_t statusBIT, u8_t* val) { + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_INT1_SRC, &value) ) + return MEMS_ERROR; + + if(statusBIT == LIS3DH_INT1_SRC_IA){ + if(value &= LIS3DH_INT1_SRC_IA){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_INT1_SRC_ZH){ + if(value &= LIS3DH_INT1_SRC_ZH){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_INT1_SRC_ZL){ + if(value &= LIS3DH_INT1_SRC_ZL){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_INT1_SRC_YH){ + if(value &= LIS3DH_INT1_SRC_YH){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_INT1_SRC_YL){ + if(value &= LIS3DH_INT1_SRC_YL){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + if(statusBIT == LIS3DH_INT1_SRC_XH){ + if(value &= LIS3DH_INT1_SRC_XH){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_INT1_SRC_XL){ + if(value &= LIS3DH_INT1_SRC_XL){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + return MEMS_ERROR; +} + + +/******************************************************************************* +* Function Name : LIS3DH_GetFifoSourceReg +* Description : Read Fifo source Register +* Input : Byte to empty by FIFO source register value +* Output : None +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetFifoSourceReg(u8_t* val) { + + if( !LIS3DH_ReadReg(LIS3DH_FIFO_SRC_REG, val) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + + +/******************************************************************************* +* Function Name : LIS3DH_GetFifoSourceBit +* Description : Read Fifo WaterMark source bit +* Input : statusBIT: LIS3DH_FIFO_SRC_WTM, LIS3DH_FIFO_SRC_OVRUN, LIS3DH_FIFO_SRC_EMPTY +* val: Byte to fill with the bit value +* Output : None +* Return : Status of BIT [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetFifoSourceBit(u8_t statusBIT, u8_t* val){ + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_FIFO_SRC_REG, &value) ) + return MEMS_ERROR; + + + if(statusBIT == LIS3DH_FIFO_SRC_WTM){ + if(value &= LIS3DH_FIFO_SRC_WTM){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + + if(statusBIT == LIS3DH_FIFO_SRC_OVRUN){ + if(value &= LIS3DH_FIFO_SRC_OVRUN){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + if(statusBIT == LIS3DH_FIFO_SRC_EMPTY){ + if(value &= statusBIT == LIS3DH_FIFO_SRC_EMPTY){ + *val = MEMS_SET; + return MEMS_SUCCESS; + } + else{ + *val = MEMS_RESET; + return MEMS_SUCCESS; + } + } + return MEMS_ERROR; +} + + +/******************************************************************************* +* Function Name : LIS3DH_GetFifoSourceFSS +* Description : Read current number of unread samples stored in FIFO +* Input : Byte to empty by FIFO unread sample value +* Output : None +* Return : Status [value of FSS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetFifoSourceFSS(u8_t* val){ + u8_t value; + + if( !LIS3DH_ReadReg(LIS3DH_FIFO_SRC_REG, &value) ) + return MEMS_ERROR; + + value &= 0x1F; + + *val = value; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_GetTempRaw +* Description : Read the Temperature Values by AUX Output Registers OUT_3_H +* Input : Buffer to empty +* Output : Temperature Values Registers buffer +* Return : Status [MEMS_ERROR, MEMS_SUCCESS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetTempRaw(i8_t* buff) { + u8_t valueL; + u8_t valueH; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_3_L, &valueL) ) + return MEMS_ERROR; + + if( !LIS3DH_ReadReg(LIS3DH_OUT_3_H, &valueH) ) + return MEMS_ERROR; + + *buff = (i8_t)( valueH ); + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_GetWHO_AM_I +* Description : Read identification code by WHO_AM_I register +* Input : Char to empty by Device identification Value +* Output : None +* Return : Status [value of FSS] +*******************************************************************************/ +status_t LIS3DH::LIS3DH_GetWHO_AM_I(u8_t* val){ + + if( !LIS3DH_ReadReg(LIS3DH_WHO_AM_I, val) ) + return MEMS_ERROR; + + return MEMS_SUCCESS; +} + +/******************************************************************************* +* Function Name : LIS3DH_ReadReg +* Description : Generic Reading function. It must be fullfilled with either +* : I2C or SPI reading functions +* Input : Register Address +* Output : Data REad +* Return : None +*******************************************************************************/ +u8_t LIS3DH::LIS3DH_ReadReg(u8_t Reg, u8_t* Data) { + + //To be completed with either I2c or SPI reading function + //i.e. *Data = SPI_Mems_Read_Reg( Reg ); + + _ss = 0; + _spi.write(0x80 | Reg); + signed char raw = _spi.write(0x00); + _ss = 1; + + *Data=raw; + + return 1; +} + +/******************************************************************************* +* Function Name : LIS3DH_WriteReg +* Description : Generic Writing function. It must be fullfilled with either +* : I2C or SPI writing function +* Input : Register Address, Data to be written +* Output : None +* Return : None +*******************************************************************************/ +u8_t LIS3DH::LIS3DH_WriteReg(u8_t WriteAddr, u8_t Data) { + + //To be completed with either I2c or SPI writing function + //i.e. SPI_Mems_Write_Reg(WriteAddr, Data); + + _ss = 0; + _spi.write(0x00 | WriteAddr); + _spi.write (Data); + _ss = 1; + + return 1; +} + +LIS3DH::~LIS3DH(){}; + \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LIS3DH.h Tue Dec 08 11:58:59 2015 +0000 @@ -0,0 +1,516 @@ +#ifndef LIS3DH_H +#define LIS3DH_H + +#include "mbed.h" + +namespace mbed { + +#ifndef __ARCHDEP__TYPES +#define __ARCHDEP__TYPES + +typedef unsigned char u8_t; +typedef unsigned short int u16_t; +typedef short int i16_t; +typedef signed char i8_t; + +#endif /*__ARCHDEP__TYPES*/ + +typedef u8_t LIS3DH_IntPinConf_t; +typedef u8_t LIS3DH_Axis_t; +typedef u8_t LIS3DH_Int1Conf_t; + + +//define structure +#ifndef __SHARED__TYPES +#define __SHARED__TYPES + +typedef enum { + MEMS_SUCCESS = 0x01, + MEMS_ERROR = 0x00 +} status_t; + +typedef enum { + MEMS_ENABLE = 0x01, + MEMS_DISABLE = 0x00 +} State_t; + +typedef __packed struct { + i16_t AXIS_X; + i16_t AXIS_Y; + i16_t AXIS_Z; +} AxesRaw_t; + +#endif /*__SHARED__TYPES*/ + +typedef enum { + LIS3DH_ODR_1Hz = 0x01, + LIS3DH_ODR_10Hz = 0x02, + LIS3DH_ODR_25Hz = 0x03, + LIS3DH_ODR_50Hz = 0x04, + LIS3DH_ODR_100Hz = 0x05, + LIS3DH_ODR_200Hz = 0x06, + LIS3DH_ODR_400Hz = 0x07, + LIS3DH_ODR_1620Hz_LP = 0x08, + LIS3DH_ODR_1344Hz_NP_5367HZ_LP = 0x09 +} LIS3DH_ODR_t; + +typedef enum { + LIS3DH_POWER_DOWN = 0x00, + LIS3DH_LOW_POWER = 0x01, + LIS3DH_NORMAL = 0x02 +} LIS3DH_Mode_t; + +typedef enum { + LIS3DH_HPM_NORMAL_MODE_RES = 0x00, + LIS3DH_HPM_REF_SIGNAL = 0x01, + LIS3DH_HPM_NORMAL_MODE = 0x02, + LIS3DH_HPM_AUTORESET_INT = 0x03 +} LIS3DH_HPFMode_t; + +typedef enum { + LIS3DH_HPFCF_0 = 0x00, + LIS3DH_HPFCF_1 = 0x01, + LIS3DH_HPFCF_2 = 0x02, + LIS3DH_HPFCF_3 = 0x03 +} LIS3DH_HPFCutOffFreq_t; + +typedef struct { + u16_t AUX_1; + u16_t AUX_2; + u16_t AUX_3; +} LIS3DH_Aux123Raw_t; + +typedef enum { + LIS3DH_FULLSCALE_2 = 0x00, + LIS3DH_FULLSCALE_4 = 0x01, + LIS3DH_FULLSCALE_8 = 0x02, + LIS3DH_FULLSCALE_16 = 0x03 +} LIS3DH_Fullscale_t; + +typedef enum { + LIS3DH_BLE_LSB = 0x00, + LIS3DH_BLE_MSB = 0x01 +} LIS3DH_Endianess_t; + +typedef enum { + LIS3DH_SELF_TEST_DISABLE = 0x00, + LIS3DH_SELF_TEST_0 = 0x01, + LIS3DH_SELF_TEST_1 = 0x02 +} LIS3DH_SelfTest_t; + +typedef enum { + LIS3DH_FIFO_BYPASS_MODE = 0x00, + LIS3DH_FIFO_MODE = 0x01, + LIS3DH_FIFO_STREAM_MODE = 0x02, + LIS3DH_FIFO_TRIGGER_MODE = 0x03, + LIS3DH_FIFO_DISABLE = 0x04 +} LIS3DH_FifoMode_t; + +typedef enum { + LIS3DH_TRIG_INT1 = 0x00, + LIS3DH_TRIG_INT2 = 0x01 +} LIS3DH_TrigInt_t; + +typedef enum { + LIS3DH_SPI_4_WIRE = 0x00, + LIS3DH_SPI_3_WIRE = 0x01 +} LIS3DH_SPIMode_t; + +typedef enum { + LIS3DH_X_ENABLE = 0x01, + LIS3DH_X_DISABLE = 0x00, + LIS3DH_Y_ENABLE = 0x02, + LIS3DH_Y_DISABLE = 0x00, + LIS3DH_Z_ENABLE = 0x04, + LIS3DH_Z_DISABLE = 0x00 +} LIS3DH_AXISenable_t; + +typedef enum { + LIS3DH_INT1_6D_4D_DISABLE = 0x00, + LIS3DH_INT1_6D_ENABLE = 0x01, + LIS3DH_INT1_4D_ENABLE = 0x02 +} LIS3DH_INT_6D_4D_t; + +typedef enum { + LIS3DH_UP_SX = 0x44, + LIS3DH_UP_DX = 0x42, + LIS3DH_DW_SX = 0x41, + LIS3DH_DW_DX = 0x48, + LIS3DH_TOP = 0x60, + LIS3DH_BOTTOM = 0x50 +} LIS3DH_POSITION_6D_t; + +typedef enum { + LIS3DH_INT_MODE_OR = 0x00, + LIS3DH_INT_MODE_6D_MOVEMENT = 0x01, + LIS3DH_INT_MODE_AND = 0x02, + LIS3DH_INT_MODE_6D_POSITION = 0x03 +} LIS3DH_Int1Mode_t; + + +//interrupt click response +// b7 = don't care b6 = IA b5 = DClick b4 = Sclick b3 = Sign +// b2 = z b1 = y b0 = x +typedef enum { +LIS3DH_DCLICK_Z_P = 0x24, +LIS3DH_DCLICK_Z_N = 0x2C, +LIS3DH_SCLICK_Z_P = 0x14, +LIS3DH_SCLICK_Z_N = 0x1C, +LIS3DH_DCLICK_Y_P = 0x22, +LIS3DH_DCLICK_Y_N = 0x2A, +LIS3DH_SCLICK_Y_P = 0x12, +LIS3DH_SCLICK_Y_N = 0x1A, +LIS3DH_DCLICK_X_P = 0x21, +LIS3DH_DCLICK_X_N = 0x29, +LIS3DH_SCLICK_X_P = 0x11, +LIS3DH_SCLICK_X_N = 0x19, +LIS3DH_NO_CLICK = 0x00 +} LIS3DH_Click_Response; + +//TODO: start from here and manage the shared macros etc before this + +/* Exported constants --------------------------------------------------------*/ + +#ifndef __SHARED__CONSTANTS +#define __SHARED__CONSTANTS + +#define MEMS_SET 0x01 +#define MEMS_RESET 0x00 + +#endif /*__SHARED__CONSTANTS*/ + + +//Register Definition +#define LIS3DH_WHO_AM_I 0x0F // device identification register (00110011 default value=0x33) + +// CONTROL REGISTER 1 +#define LIS3DH_CTRL_REG1 0x20 +#define LIS3DH_ODR_BIT BIT(4) +#define LIS3DH_LPEN BIT(3) +#define LIS3DH_ZEN BIT(2) +#define LIS3DH_YEN BIT(1) +#define LIS3DH_XEN BIT(0) + +//CONTROL REGISTER 2 +#define LIS3DH_CTRL_REG2 0x21 +#define LIS3DH_HPM BIT(6) +#define LIS3DH_HPCF BIT(4) +#define LIS3DH_FDS BIT(3) +#define LIS3DH_HPCLICK BIT(2) +#define LIS3DH_HPIS2 BIT(1) +#define LIS3DH_HPIS1 BIT(0) + +//CONTROL REGISTER 3 +#define LIS3DH_CTRL_REG3 0x22 +#define LIS3DH_I1_CLICK BIT(7) +#define LIS3DH_I1_AOI1 BIT(6) +#define LIS3DH_I1_AOI2 BIT(5) +#define LIS3DH_I1_DRDY1 BIT(4) +#define LIS3DH_I1_DRDY2 BIT(3) +#define LIS3DH_I1_WTM BIT(2) +#define LIS3DH_I1_ORUN BIT(1) + +//CONTROL REGISTER 6 +#define LIS3DH_CTRL_REG6 0x25 +#define LIS3DH_I2_CLICK BIT(7) +#define LIS3DH_I2_INT1 BIT(6) +#define LIS3DH_I2_BOOT BIT(4) +#define LIS3DH_H_LACTIVE BIT(1) + +//TEMPERATURE CONFIG REGISTER +#define LIS3DH_TEMP_CFG_REG 0x1F +#define LIS3DH_ADC_PD BIT(7) +#define LIS3DH_TEMP_EN BIT(6) + +//CONTROL REGISTER 4 +#define LIS3DH_CTRL_REG4 0x23 +#define LIS3DH_BDU BIT(7) +#define LIS3DH_BLE BIT(6) +#define LIS3DH_FS BIT(4) +#define LIS3DH_HR BIT(3) +#define LIS3DH_ST BIT(1) +#define LIS3DH_SIM BIT(0) + +//CONTROL REGISTER 5 +#define LIS3DH_CTRL_REG5 0x24 +#define LIS3DH_BOOT BIT(7) +#define LIS3DH_FIFO_EN BIT(6) +#define LIS3DH_LIR_INT1 BIT(3) +#define LIS3DH_D4D_INT1 BIT(2) + +//REFERENCE/DATA_CAPTURE +#define LIS3DH_REFERENCE_REG 0x26 +#define LIS3DH_REF BIT(0) + +//STATUS_REG_AXIES +#define LIS3DH_STATUS_REG 0x27 +#define LIS3DH_ZYXOR BIT(7) +#define LIS3DH_ZOR BIT(6) +#define LIS3DH_YOR BIT(5) +#define LIS3DH_XOR BIT(4) +#define LIS3DH_ZYXDA BIT(3) +#define LIS3DH_ZDA BIT(2) +#define LIS3DH_YDA BIT(1) +#define LIS3DH_XDA BIT(0) + +//STATUS_REG_AUX +#define LIS3DH_STATUS_AUX 0x07 + +//INTERRUPT 1 CONFIGURATION +#define LIS3DH_INT1_CFG 0x30 +#define LIS3DH_ANDOR BIT(7) +#define LIS3DH_INT_6D BIT(6) +#define LIS3DH_ZHIE BIT(5) +#define LIS3DH_ZLIE BIT(4) +#define LIS3DH_YHIE BIT(3) +#define LIS3DH_YLIE BIT(2) +#define LIS3DH_XHIE BIT(1) +#define LIS3DH_XLIE BIT(0) + +//FIFO CONTROL REGISTER +#define LIS3DH_FIFO_CTRL_REG 0x2E +#define LIS3DH_FM BIT(6) +#define LIS3DH_TR BIT(5) +#define LIS3DH_FTH BIT(0) + +//CONTROL REG3 bit mask +#define LIS3DH_CLICK_ON_PIN_INT1_ENABLE 0x80 +#define LIS3DH_CLICK_ON_PIN_INT1_DISABLE 0x00 +#define LIS3DH_I1_INT1_ON_PIN_INT1_ENABLE 0x40 +#define LIS3DH_I1_INT1_ON_PIN_INT1_DISABLE 0x00 +#define LIS3DH_I1_INT2_ON_PIN_INT1_ENABLE 0x20 +#define LIS3DH_I1_INT2_ON_PIN_INT1_DISABLE 0x00 +#define LIS3DH_I1_DRDY1_ON_INT1_ENABLE 0x10 +#define LIS3DH_I1_DRDY1_ON_INT1_DISABLE 0x00 +#define LIS3DH_I1_DRDY2_ON_INT1_ENABLE 0x08 +#define LIS3DH_I1_DRDY2_ON_INT1_DISABLE 0x00 +#define LIS3DH_WTM_ON_INT1_ENABLE 0x04 +#define LIS3DH_WTM_ON_INT1_DISABLE 0x00 +#define LIS3DH_INT1_OVERRUN_ENABLE 0x02 +#define LIS3DH_INT1_OVERRUN_DISABLE 0x00 + +//CONTROL REG6 bit mask +#define LIS3DH_CLICK_ON_PIN_INT2_ENABLE 0x80 +#define LIS3DH_CLICK_ON_PIN_INT2_DISABLE 0x00 +#define LIS3DH_I2_INT1_ON_PIN_INT2_ENABLE 0x40 +#define LIS3DH_I2_INT1_ON_PIN_INT2_DISABLE 0x00 +#define LIS3DH_I2_INT2_ON_PIN_INT2_ENABLE 0x20 +#define LIS3DH_I2_INT2_ON_PIN_INT2_DISABLE 0x00 +#define LIS3DH_I2_BOOT_ON_INT2_ENABLE 0x10 +#define LIS3DH_I2_BOOT_ON_INT2_DISABLE 0x00 +#define LIS3DH_INT_ACTIVE_HIGH 0x00 +#define LIS3DH_INT_ACTIVE_LOW 0x02 + +//INT1_CFG bit mask +#define LIS3DH_INT1_AND 0x80 +#define LIS3DH_INT1_OR 0x00 +#define LIS3DH_INT1_ZHIE_ENABLE 0x20 +#define LIS3DH_INT1_ZHIE_DISABLE 0x00 +#define LIS3DH_INT1_ZLIE_ENABLE 0x10 +#define LIS3DH_INT1_ZLIE_DISABLE 0x00 +#define LIS3DH_INT1_YHIE_ENABLE 0x08 +#define LIS3DH_INT1_YHIE_DISABLE 0x00 +#define LIS3DH_INT1_YLIE_ENABLE 0x04 +#define LIS3DH_INT1_YLIE_DISABLE 0x00 +#define LIS3DH_INT1_XHIE_ENABLE 0x02 +#define LIS3DH_INT1_XHIE_DISABLE 0x00 +#define LIS3DH_INT1_XLIE_ENABLE 0x01 +#define LIS3DH_INT1_XLIE_DISABLE 0x00 + +//INT1_SRC bit mask +#define LIS3DH_INT1_SRC_IA 0x40 +#define LIS3DH_INT1_SRC_ZH 0x20 +#define LIS3DH_INT1_SRC_ZL 0x10 +#define LIS3DH_INT1_SRC_YH 0x08 +#define LIS3DH_INT1_SRC_YL 0x04 +#define LIS3DH_INT1_SRC_XH 0x02 +#define LIS3DH_INT1_SRC_XL 0x01 + +//INT1 REGISTERS +#define LIS3DH_INT1_THS 0x32 +#define LIS3DH_INT1_DURATION 0x33 + +//INTERRUPT 1 SOURCE REGISTER +#define LIS3DH_INT1_SRC 0x31 + +//FIFO Source Register bit Mask +#define LIS3DH_FIFO_SRC_WTM 0x80 +#define LIS3DH_FIFO_SRC_OVRUN 0x40 +#define LIS3DH_FIFO_SRC_EMPTY 0x20 + +//INTERRUPT CLICK REGISTER +#define LIS3DH_CLICK_CFG 0x38 +//INTERRUPT CLICK CONFIGURATION bit mask +#define LIS3DH_ZD_ENABLE 0x20 +#define LIS3DH_ZD_DISABLE 0x00 +#define LIS3DH_ZS_ENABLE 0x10 +#define LIS3DH_ZS_DISABLE 0x00 +#define LIS3DH_YD_ENABLE 0x08 +#define LIS3DH_YD_DISABLE 0x00 +#define LIS3DH_YS_ENABLE 0x04 +#define LIS3DH_YS_DISABLE 0x00 +#define LIS3DH_XD_ENABLE 0x02 +#define LIS3DH_XD_DISABLE 0x00 +#define LIS3DH_XS_ENABLE 0x01 +#define LIS3DH_XS_DISABLE 0x00 + +//INTERRUPT CLICK SOURCE REGISTER +#define LIS3DH_CLICK_SRC 0x39 +//INTERRUPT CLICK SOURCE REGISTER bit mask +#define LIS3DH_IA 0x40 +#define LIS3DH_DCLICK 0x20 +#define LIS3DH_SCLICK 0x10 +#define LIS3DH_CLICK_SIGN 0x08 +#define LIS3DH_CLICK_Z 0x04 +#define LIS3DH_CLICK_Y 0x02 +#define LIS3DH_CLICK_X 0x01 + +//Click-click Register +#define LIS3DH_CLICK_THS 0x3A +#define LIS3DH_TIME_LIMIT 0x3B +#define LIS3DH_TIME_LATENCY 0x3C +#define LIS3DH_TIME_WINDOW 0x3D + +//OUTPUT REGISTER +#define LIS3DH_OUT_X_L 0x28 +#define LIS3DH_OUT_X_H 0x29 +#define LIS3DH_OUT_Y_L 0x2A +#define LIS3DH_OUT_Y_H 0x2B +#define LIS3DH_OUT_Z_L 0x2C +#define LIS3DH_OUT_Z_H 0x2D + +//AUX REGISTER +#define LIS3DH_OUT_1_L 0x08 +#define LIS3DH_OUT_1_H 0x09 +#define LIS3DH_OUT_2_L 0x0A +#define LIS3DH_OUT_2_H 0x0B +#define LIS3DH_OUT_3_L 0x0C +#define LIS3DH_OUT_3_H 0x0D + +//STATUS REGISTER bit mask +#define LIS3DH_STATUS_REG_ZYXOR 0x80 // 1 : new data set has over written the previous one + // 0 : no overrun has occurred (default) +#define LIS3DH_STATUS_REG_ZOR 0x40 // 0 : no overrun has occurred (default) + // 1 : new Z-axis data has over written the previous one +#define LIS3DH_STATUS_REG_YOR 0x20 // 0 : no overrun has occurred (default) + // 1 : new Y-axis data has over written the previous one +#define LIS3DH_STATUS_REG_XOR 0x10 // 0 : no overrun has occurred (default) + // 1 : new X-axis data has over written the previous one +#define LIS3DH_STATUS_REG_ZYXDA 0x08 // 0 : a new set of data is not yet avvious one + // 1 : a new set of data is available +#define LIS3DH_STATUS_REG_ZDA 0x04 // 0 : a new data for the Z-Axis is not availvious one + // 1 : a new data for the Z-Axis is available +#define LIS3DH_STATUS_REG_YDA 0x02 // 0 : a new data for the Y-Axis is not available + // 1 : a new data for the Y-Axis is available +#define LIS3DH_STATUS_REG_XDA 0x01 // 0 : a new data for the X-Axis is not available + +#define LIS3DH_DATAREADY_BIT LIS3DH_STATUS_REG_ZYXDA + + +//STATUS AUX REGISTER bit mask +#define LIS3DH_STATUS_AUX_321OR 0x80 +#define LIS3DH_STATUS_AUX_3OR 0x40 +#define LIS3DH_STATUS_AUX_2OR 0x20 +#define LIS3DH_STATUS_AUX_1OR 0x10 +#define LIS3DH_STATUS_AUX_321DA 0x08 +#define LIS3DH_STATUS_AUX_3DA 0x04 +#define LIS3DH_STATUS_AUX_2DA 0x02 +#define LIS3DH_STATUS_AUX_1DA 0x01 + +#define LIS3DH_MEMS_I2C_ADDRESS 0x33 + +//FIFO REGISTERS +#define LIS3DH_FIFO_CTRL_REG 0x2E +#define LIS3DH_FIFO_SRC_REG 0x2F + + +/* Exported macro ------------------------------------------------------------*/ + +#ifndef __SHARED__MACROS + +#define __SHARED__MACROS +#define ValBit(VAR,Place) (VAR & (1<<Place)) +#define BIT(x) ( (x) ) + +#endif /*__SHARED__MACROS*/ + +class LIS3DH +{ +public: + LIS3DH(PinName mosi, PinName miso, PinName ss, PinName sck); + ~LIS3DH(); + + //own functions + u8_t InitLIS3DH(LIS3DH_Mode_t Mode, LIS3DH_ODR_t Odr, LIS3DH_Fullscale_t Grange); + u8_t SetLIS3DHActivityDetection(uint8_t Th, LIS3DH_Int1Mode_t Mode, uint8_t OnOff); + + //Sensor Configuration Functions + status_t LIS3DH_SetODR(LIS3DH_ODR_t ov); + status_t LIS3DH_SetMode(LIS3DH_Mode_t md); + status_t LIS3DH_SetAxis(LIS3DH_Axis_t axis); + status_t LIS3DH_SetFullScale(LIS3DH_Fullscale_t fs); + status_t LIS3DH_SetBDU(State_t bdu); + status_t LIS3DH_SetBLE(LIS3DH_Endianess_t ble); + status_t LIS3DH_SetSelfTest(LIS3DH_SelfTest_t st); + status_t LIS3DH_SetTemperature(State_t state); + status_t LIS3DH_SetADCAux(State_t state); + + //Filtering Functions + status_t LIS3DH_HPFClickEnable(State_t hpfe); + status_t LIS3DH_HPFAOI1Enable(State_t hpfe); + status_t LIS3DH_HPFAOI2Enable(State_t hpfe); + status_t LIS3DH_SetHPFMode(LIS3DH_HPFMode_t hpf); + status_t LIS3DH_SetHPFCutOFF(LIS3DH_HPFCutOffFreq_t hpf); + status_t LIS3DH_SetFilterDataSel(State_t state); + + //Interrupt Functions + status_t LIS3DH_SetInt1Pin(LIS3DH_IntPinConf_t pinConf); + status_t LIS3DH_SetInt2Pin(LIS3DH_IntPinConf_t pinConf); + status_t LIS3DH_Int1LatchEnable(State_t latch); + status_t LIS3DH_ResetInt1Latch(void); + status_t LIS3DH_SetIntConfiguration(LIS3DH_Int1Conf_t ic); + status_t LIS3DH_SetInt1Threshold(u8_t ths); + status_t LIS3DH_SetInt1Duration(LIS3DH_Int1Conf_t id); + status_t LIS3DH_SetIntMode(LIS3DH_Int1Mode_t ic); + status_t LIS3DH_SetClickCFG(u8_t status); + status_t LIS3DH_SetClickTHS(u8_t ths); + status_t LIS3DH_SetClickLIMIT(u8_t t_limit); + status_t LIS3DH_SetClickLATENCY(u8_t t_latency); + status_t LIS3DH_SetClickWINDOW(u8_t t_window); + status_t LIS3DH_SetInt6D4DConfiguration(LIS3DH_INT_6D_4D_t ic); + status_t LIS3DH_GetInt1Src(u8_t* val); + status_t LIS3DH_GetInt1SrcBit(u8_t statusBIT, u8_t* val); + + //FIFO Functions + status_t LIS3DH_FIFOModeEnable(LIS3DH_FifoMode_t fm); + status_t LIS3DH_SetWaterMark(u8_t wtm); + status_t LIS3DH_SetTriggerInt(LIS3DH_TrigInt_t tr); + status_t LIS3DH_GetFifoSourceReg(u8_t* val); + status_t LIS3DH_GetFifoSourceBit(u8_t statusBIT, u8_t* val); + status_t LIS3DH_GetFifoSourceFSS(u8_t* val); + + //Other Reading Functions + status_t LIS3DH_GetStatusReg(u8_t* val); + status_t LIS3DH_GetStatusBit(u8_t statusBIT, u8_t* val); + status_t LIS3DH_GetStatusAUXBit(u8_t statusBIT, u8_t* val); + status_t LIS3DH_GetStatusAUX(u8_t* val); + + status_t LIS3DH_GetAccAxesRaw(AxesRaw_t* buff); + status_t LIS3DH_GetAuxRaw(LIS3DH_Aux123Raw_t* buff); + status_t LIS3DH_GetClickResponse(u8_t* val); + status_t LIS3DH_GetTempRaw(i8_t* val); + status_t LIS3DH_GetWHO_AM_I(u8_t* val); + status_t LIS3DH_Get6DPosition(u8_t* val); + +private: + u8_t LIS3DH_ReadReg(u8_t Reg, u8_t* Data); + u8_t LIS3DH_WriteReg(u8_t WriteAddr, u8_t Data); + + +protected: + SPI _spi; + DigitalOut _ss; + +}; +} //Namespace +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Dec 08 11:58:59 2015 +0000 @@ -0,0 +1,249 @@ +#include "mbed.h" +#include "ble/BLE.h" + +#define USE_DFU + +#ifdef USE_DFU +#include "DFUService.h" +#endif + +#include "AT45.h" +#include "LIS3DH.h" + +//interrupt /gpio configuration +#include "nrf_gpio.h" +#include "nrf_gpiote.h" +#include "nrf_soc.h" + +//SPI stuff +#define MOSI p8 +#define MISO p9 +#define SCLK p7 +#define CS p2 + +//#include "app_error.h" +//void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name) { } + +//const static char DEVICE_NAME[] = "BAc0N"; +//static const uint16_t uuid16_list[] = {GattService::UUID_STREAMING_SERVICE}; + +BLE ble; + +static LIS3DH lis(MOSI, MISO, CS, SCLK); + +#define LED_0 p20 +#define LED_1 p23 +//#define LED_2 p24 +DigitalOut myled1(LED_0); +DigitalOut myled2(LED_1); +//DigitalOut myled3(LED_2); + +//#define UART_TX p17 +//#define UART_RX p18 +//Serial pc(UART_TX, UART_RX); // tx, rx + + +/** @brief Function for initializing the GPIO Tasks/Events peripheral. +*/ +static void gpiote_init(void) +{ + // Configure accelerometer interrupt pin + nrf_gpio_cfg_input(3, NRF_GPIO_PIN_PULLDOWN); + //nrf_gpio_cfg_input(4, NRF_GPIO_PIN_PULLDOWN); + + // Configure GPIOTE channel 0 to generate event when MOTION_INTERRUPT_PIN_NUMBER goes from Low to High + nrf_gpiote_event_config(0, 3, NRF_GPIOTE_POLARITY_LOTOHI); //accelerometer int1 + //nrf_gpiote_event_config(1, 4, NRF_GPIOTE_POLARITY_LOTOHI); //accelerometer int2 + + // Enable interrupt for NRF_GPIOTE->EVENTS_IN[0] event + NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN0_Msk; + //NRF_GPIOTE->INTENSET |= GPIOTE_INTENSET_IN1_Msk; +} + +extern "C" +void GPIOTE_IRQHandler(void) +{ + // Event causing the interrupt must be cleared + NRF_GPIOTE->EVENTS_IN[0] = 0; + //NRF_GPIOTE->EVENTS_IN[1] = 0; + lis.LIS3DH_ResetInt1Latch(); + + myled1 = !myled1; + myled2 = !myled2; +} + +void disconnect_input_buffers() +{ + for(uint8_t i = 0; i < 3; i++) + { + NRF_GPIO->PIN_CNF[i] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) + | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) + | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) + | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) + | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); + } + //Omit accelerometer interrupt pins (3&4) + for(uint8_t i = 5; i < 21; i++) + { + NRF_GPIO->PIN_CNF[i] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) + | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) + | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) + | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) + | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); + } + //Omit I2C pins (21 & 22) + for(uint8_t i = 23; i < 31; i++) + { + NRF_GPIO->PIN_CNF[i] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) + | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) + | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) + | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) + | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); + } +} + +__packed struct ApplicationData_t { + uint16_t applicationSpecificId; /* An ID used to identify temperature value in the manufacture specific AD data field */ + //TMP_nrf51::tmpSensorValue_t tmpSensorValue; /* User defined application data */ + int8_t accel_temp; + //uint16_t lis; + AxesRaw_t accel_raw; +}; + +void setupApplicationData(ApplicationData_t &appData) +{ + static const uint16_t APP_SPECIFIC_ID_TEST = 0xFEFE; + appData.applicationSpecificId = APP_SPECIFIC_ID_TEST; + //appData.tmpSensorValue = tempSensor.get(); + lis.LIS3DH_GetAccAxesRaw(&appData.accel_raw); + lis.LIS3DH_GetTempRaw(&appData.accel_temp); + //uint8_t asdf; + //lis.LIS3DH_GetWHO_AM_I(&asdf); + //uint8_t val = 100; + //appData.lis = (asdf << 8) | val; + + //appData.lis = lis.whoami(); +} + +void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) +{ + ble.gap().startAdvertising(); +} + +void senseCallback(void) +{ + ApplicationData_t appData; + setupApplicationData(appData); + ble.gap().updateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&appData, sizeof(ApplicationData_t)); +} + +int main() +{ + + //LEDS off + myled1 = 0; + myled2 = 0; + //myled3 = 0; + + //Without this setup CS lines of AT45 & LIS3DH are in conflict, causing huge current consumption + //i.e. both are connected to same SPI interface at the same time + #if defined(TARGET_NRF51822_NODE_V3_OTA) || defined(TARGET_NRF51822_NODE_V3) || defined(TARGET_NRF51822_NODE_V3_BOOT) + DigitalOut LIS_CS_0(CS); + LIS_CS_0 = 1; //not selected + + DigitalOut AT_CS(p5); + DigitalOut AT_RS(p6); + + AT_CS = 1; //not selected + AT_RS = 0; //asserted == reset state + wait_ms(100); + AT_RS = 1; + #endif + + //Initialize SPI interface + SPI spi(MOSI, MISO, SCLK); // mosi, miso, sclk + spi.format(8,3); + spi.frequency(8000000); + //setup AT45 dataflash to powersaving mode + AT45* flash = new AT45(spi, p5); + flash->ultra_deep_power_down(true); + + //Accelerometer interrupt pin configuration + gpiote_init(); + + //Disconnect input buffers to save power + //disabled for testing + //disconnect_input_buffers(); + + //Initialize LIS3DH driver + lis.InitLIS3DH(LIS3DH_NORMAL, LIS3DH_ODR_100Hz, LIS3DH_FULLSCALE_2); //Init Acc-sensor + //lis.LIS3DH_SetTemperature(MEMS_ENABLE); + //lis.LIS3DH_SetADCAux(MEMS_ENABLE); + //lis.LIS3DH_SetBDU(MEMS_ENABLE); + //enable threshold to generate interrupt + lis.SetLIS3DHActivityDetection(3, LIS3DH_INT_MODE_6D_POSITION, 1); + //disable... + //lis.SetLIS3DHActivityDetection(20, LIS3DH_INT_MODE_OR, 0); + + // Enable GPIOTE interrupt in Nested Vector Interrupt Controller. + NVIC_ClearPendingIRQ(GPIOTE_IRQn); + NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Set << GPIOTE_INTENSET_PORT_Pos; + NVIC_SetPriority(GPIOTE_IRQn, 1); + NVIC_EnableIRQ(GPIOTE_IRQn); + //sd_nvic_EnableIRQ(GPIOTE_IRQn); + + //osDelay(osWaitForever); + //Was Getting 13.2uA with these settings (flash deep power down). + //With ultra deep power down 7.8uA... rose back to ~11uA??? Seems to fluctuate. Now getting 9.4... IO issue? + //Now getting 5.4uA + + //device current + //3.8uA idle (SYSTEM-ON base current with 32 kB RAM enabled.). Executing code from flash memory 4.1uA. From ram 2.4uA + //32.768 kHz crystal oscillator 0.4uA / 32.768 kHz RC oscillator (32k RCOSC) 1.1uA (kumpi on?) + //RTC Timer (LFCLK source) 0.1uA + //==3.8 + (0.4) + 0.1uA + 5*0.1 (digitalout active) = 4.8uA + + //(watchdog) 0.1uA + //GPIO as input = 22uA (Run current with 1 or more GPIOTE active channels in Input mode.) + //as output 0.1A (Run current with 1 or more GPIOTE active channels in Output mode) + + //Peripherals current + //BMP 180 0.1uA standby, 5uA standard mode, 7uA high resolution mode + //LIS3DH 0.5uA standby mode, varies a lot in measurement mode + //Si7021 0.06uA standby mode, 150uA active + //AT45 Ultra deep power down 0,4uA, deep power down 5uA. Standby 25uA. 11mA active + //== 0.1uA + 0.5uA + 0.06uA + 0.4uA = 1.06uA + + //total should be ~5.86 (or 5.46 depending on whether oscillator is included in system idle current) + + //Initialize BLE stuff + ble.init(); + ble.gap().onDisconnection(disconnectionCallback); + + #ifdef USE_DFU + DFUService dfu(ble); + #endif + + /* Setup advertising. */ + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_THERMOMETER); + ApplicationData_t appData; + setupApplicationData(appData); + //ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); + //ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&appData, sizeof(ApplicationData_t)); + + ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); + //ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); + ble.gap().setAdvertisingInterval(100); /* 1000ms. */ + ble.gap().startAdvertising(); + + Ticker ticker; + ticker.attach(senseCallback, 0.1); + + ///Could have main loop here doing something + while(true) { + ble.waitForEvent(); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Dec 08 11:58:59 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/165afa46840b \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nRF51822.lib Tue Dec 08 11:58:59 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#bcfe7a90edb9
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nrf_gpio.h Tue Dec 08 11:58:59 2015 +0000 @@ -0,0 +1,422 @@ +#ifndef NRF_GPIO_H__ +#define NRF_GPIO_H__ + +#include "nrf51.h" +#include "nrf51_bitfields.h" + +/** + * @defgroup nrf_gpio GPIO abstraction + * @{ + * @ingroup nrf_drivers + * @brief GPIO pin abstraction and port abstraction for reading and writing byte-wise to GPIO ports. + * + * Here, the GPIO ports are defined as follows: + * - Port 0 -> pin 0-7 + * - Port 1 -> pin 8-15 + * - Port 2 -> pin 16-23 + * - Port 3 -> pin 24-31 + */ + +/** + * @enum nrf_gpio_port_dir_t + * @brief Enumerator used for setting the direction of a GPIO port. + */ +typedef enum +{ + NRF_GPIO_PORT_DIR_OUTPUT, ///< Output + NRF_GPIO_PORT_DIR_INPUT ///< Input +} nrf_gpio_port_dir_t; + +/** + * @enum nrf_gpio_pin_dir_t + * Pin direction definitions. + */ +typedef enum +{ + NRF_GPIO_PIN_DIR_INPUT, ///< Input + NRF_GPIO_PIN_DIR_OUTPUT ///< Output +} nrf_gpio_pin_dir_t; + +/** + * @enum nrf_gpio_port_select_t + * @brief Enumerator used for selecting between port 0 - 3. + */ +typedef enum +{ + NRF_GPIO_PORT_SELECT_PORT0 = 0, ///< Port 0 (GPIO pin 0-7) + NRF_GPIO_PORT_SELECT_PORT1, ///< Port 1 (GPIO pin 8-15) + NRF_GPIO_PORT_SELECT_PORT2, ///< Port 2 (GPIO pin 16-23) + NRF_GPIO_PORT_SELECT_PORT3, ///< Port 3 (GPIO pin 24-31) +} nrf_gpio_port_select_t; + +/** + * @enum nrf_gpio_pin_pull_t + * @brief Enumerator used for selecting the pin to be pulled down or up at the time of pin configuration + */ +typedef enum +{ + NRF_GPIO_PIN_NOPULL = GPIO_PIN_CNF_PULL_Disabled, ///< Pin pullup resistor disabled + NRF_GPIO_PIN_PULLDOWN = GPIO_PIN_CNF_PULL_Pulldown, ///< Pin pulldown resistor enabled + NRF_GPIO_PIN_PULLUP = GPIO_PIN_CNF_PULL_Pullup, ///< Pin pullup resistor enabled +} nrf_gpio_pin_pull_t; + +/** + * @enum nrf_gpio_pin_sense_t + * @brief Enumerator used for selecting the pin to sense high or low level on the pin input. + */ +typedef enum +{ + NRF_GPIO_PIN_NOSENSE = GPIO_PIN_CNF_SENSE_Disabled, ///< Pin sense level disabled. + NRF_GPIO_PIN_SENSE_LOW = GPIO_PIN_CNF_SENSE_Low, ///< Pin sense low level. + NRF_GPIO_PIN_SENSE_HIGH = GPIO_PIN_CNF_SENSE_High, ///< Pin sense high level. +} nrf_gpio_pin_sense_t; + +/** + * @brief Function for configuring the GPIO pin range as outputs with normal drive strength. + * This function can be used to configure pin range as simple output with gate driving GPIO_PIN_CNF_DRIVE_S0S1 (normal cases). + * + * @param pin_range_start specifies the start number (inclusive) in the range of pin numbers to be configured (allowed values 0-30) + * + * @param pin_range_end specifies the end number (inclusive) in the range of pin numbers to be configured (allowed values 0-30) + * + * @note For configuring only one pin as output use @ref nrf_gpio_cfg_output + * Sense capability on the pin is disabled, and input is disconnected from the buffer as the pins are configured as output. + */ +static __INLINE void nrf_gpio_range_cfg_output(uint32_t pin_range_start, uint32_t pin_range_end) +{ + /*lint -e{845} // A zero has been given as right argument to operator '|'" */ + for (; pin_range_start <= pin_range_end; pin_range_start++) + { + NRF_GPIO->PIN_CNF[pin_range_start] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) + | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) + | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) + | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) + | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); + } +} + +/** + * @brief Function for configuring the GPIO pin range as inputs with given initial value set, hiding inner details. + * This function can be used to configure pin range as simple input. + * + * @param pin_range_start specifies the start number (inclusive) in the range of pin numbers to be configured (allowed values 0-30) + * + * @param pin_range_end specifies the end number (inclusive) in the range of pin numbers to be configured (allowed values 0-30) + * + * @param pull_config State of the pin range pull resistor (no pull, pulled down or pulled high) + * + * @note For configuring only one pin as input use @ref nrf_gpio_cfg_input + * Sense capability on the pin is disabled, and input is connected to buffer so that the GPIO->IN register is readable + */ +static __INLINE void nrf_gpio_range_cfg_input(uint32_t pin_range_start, uint32_t pin_range_end, nrf_gpio_pin_pull_t pull_config) +{ + /*lint -e{845} // A zero has been given as right argument to operator '|'" */ + for (; pin_range_start <= pin_range_end; pin_range_start++) + { + NRF_GPIO->PIN_CNF[pin_range_start] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) + | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) + | (pull_config << GPIO_PIN_CNF_PULL_Pos) + | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) + | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); + } +} + +/** + * @brief Function for configuring the given GPIO pin number as output with given initial value set, hiding inner details. + * This function can be used to configure pin range as simple input with gate driving GPIO_PIN_CNF_DRIVE_S0S1 (normal cases). + * + * @param pin_number specifies the pin number of gpio pin numbers to be configured (allowed values 0-30) + * + * @note Sense capability on the pin is disabled, and input is disconnected from the buffer as the pins are configured as output. + */ +static __INLINE void nrf_gpio_cfg_output(uint32_t pin_number) +{ + /*lint -e{845} // A zero has been given as right argument to operator '|'" */ + NRF_GPIO->PIN_CNF[pin_number] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) + | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) + | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) + | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) + | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos); +} + +/** + * @brief Function for configuring the given GPIO pin number as input with given initial value set, hiding inner details. + * This function can be used to configure pin range as simple input with gate driving GPIO_PIN_CNF_DRIVE_S0S1 (normal cases). + * + * @param pin_number specifies the pin number of gpio pin numbers to be configured (allowed values 0-30) + * + * @param pull_config State of the pin range pull resistor (no pull, pulled down or pulled high) + * + * @note Sense capability on the pin is disabled, and input is connected to buffer so that the GPIO->IN register is readable + */ +static __INLINE void nrf_gpio_cfg_input(uint32_t pin_number, nrf_gpio_pin_pull_t pull_config) +{ + /*lint -e{845} // A zero has been given as right argument to operator '|'" */ + NRF_GPIO->PIN_CNF[pin_number] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) + | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) + | (pull_config << GPIO_PIN_CNF_PULL_Pos) + | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) + | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); +} + +/** + * @brief Function for configuring the given GPIO pin number as input with given initial value set, hiding inner details. + * This function can be used to configure pin range as simple input with gate driving GPIO_PIN_CNF_DRIVE_S0S1 (normal cases). + * Sense capability on the pin is configurable, and input is connected to buffer so that the GPIO->IN register is readable. + * + * @param pin_number specifies the pin number of gpio pin numbers to be configured (allowed values 0-30). + * + * @param pull_config state of the pin pull resistor (no pull, pulled down or pulled high). + * + * @param sense_config sense level of the pin (no sense, sense low or sense high). + */ +static __INLINE void nrf_gpio_cfg_sense_input(uint32_t pin_number, nrf_gpio_pin_pull_t pull_config, nrf_gpio_pin_sense_t sense_config) +{ + /*lint -e{845} // A zero has been given as right argument to operator '|'" */ + NRF_GPIO->PIN_CNF[pin_number] = (sense_config << GPIO_PIN_CNF_SENSE_Pos) + | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) + | (pull_config << GPIO_PIN_CNF_PULL_Pos) + | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) + | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); +} + +/** + * @brief Function for setting the direction for a GPIO pin. + * + * @param pin_number specifies the pin number [0:31] for which to + * set the direction. + * + * @param direction specifies the direction + */ +static __INLINE void nrf_gpio_pin_dir_set(uint32_t pin_number, nrf_gpio_pin_dir_t direction) +{ + if(direction == NRF_GPIO_PIN_DIR_INPUT) + { + NRF_GPIO->PIN_CNF[pin_number] = + (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) + | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) + | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) + | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) + | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos); + } + else + { + NRF_GPIO->DIRSET = (1UL << pin_number); + } +} + +/** + * @brief Function for setting a GPIO pin. + * + * Note that the pin must be configured as an output for this + * function to have any effect. + * + * @param pin_number specifies the pin number [0:31] to + * set. + */ +static __INLINE void nrf_gpio_pin_set(uint32_t pin_number) +{ + NRF_GPIO->OUTSET = (1UL << pin_number); +} + +/** + * @brief Function for clearing a GPIO pin. + * + * Note that the pin must be configured as an output for this + * function to have any effect. + * + * @param pin_number specifies the pin number [0:31] to + * clear. + */ +static __INLINE void nrf_gpio_pin_clear(uint32_t pin_number) +{ + NRF_GPIO->OUTCLR = (1UL << pin_number); +} + +/** + * @brief Function for toggling a GPIO pin. + * + * Note that the pin must be configured as an output for this + * function to have any effect. + * + * @param pin_number specifies the pin number [0:31] to + * toggle. + */ +static __INLINE void nrf_gpio_pin_toggle(uint32_t pin_number) +{ + const uint32_t pin_bit = 1UL << pin_number; + const uint32_t pin_state = ((NRF_GPIO->OUT >> pin_number) & 1UL); + + if (pin_state == 0) + { + // Current state low, set high. + NRF_GPIO->OUTSET = pin_bit; + } + else + { + // Current state high, set low. + NRF_GPIO->OUTCLR = pin_bit; + } +} + +/** + * @brief Function for writing a value to a GPIO pin. + * + * Note that the pin must be configured as an output for this + * function to have any effect. + * + * @param pin_number specifies the pin number [0:31] to + * write. + * + * @param value specifies the value to be written to the pin. + * @arg 0 clears the pin + * @arg >=1 sets the pin. + */ +static __INLINE void nrf_gpio_pin_write(uint32_t pin_number, uint32_t value) +{ + if (value == 0) + { + nrf_gpio_pin_clear(pin_number); + } + else + { + nrf_gpio_pin_set(pin_number); + } +} + +/** + * @brief Function for reading the input level of a GPIO pin. + * + * Note that the pin must have input connected for the value + * returned from this function to be valid. + * + * @param pin_number specifies the pin number [0:31] to + * read. + * + * @return + * @retval 0 if the pin input level is low. + * @retval 1 if the pin input level is high. + * @retval > 1 should never occur. + */ +static __INLINE uint32_t nrf_gpio_pin_read(uint32_t pin_number) +{ + return ((NRF_GPIO->IN >> pin_number) & 1UL); +} + +/** + * @brief Generic function for writing a single byte of a 32 bit word at a given + * address. + * + * This function should not be called from outside the nrf_gpio + * abstraction layer. + * + * @param word_address is the address of the word to be written. + * + * @param byte_no is the the word byte number (0-3) to be written. + * + * @param value is the value to be written to byte "byte_no" of word + * at address "word_address" + */ +static __INLINE void nrf_gpio_word_byte_write(volatile uint32_t * word_address, uint8_t byte_no, uint8_t value) +{ + *((volatile uint8_t*)(word_address) + byte_no) = value; +} + +/** + * @brief Generic function for reading a single byte of a 32 bit word at a given + * address. + * + * This function should not be called from outside the nrf_gpio + * abstraction layer. + * + * @param word_address is the address of the word to be read. + * + * @param byte_no is the the byte number (0-3) of the word to be read. + * + * @return byte "byte_no" of word at address "word_address". + */ +static __INLINE uint8_t nrf_gpio_word_byte_read(const volatile uint32_t* word_address, uint8_t byte_no) +{ + return (*((const volatile uint8_t*)(word_address) + byte_no)); +} + +/** + * @brief Function for setting the direction of a port. + * + * @param port is the port for which to set the direction. + * + * @param dir direction to be set for this port. + */ +static __INLINE void nrf_gpio_port_dir_set(nrf_gpio_port_select_t port, nrf_gpio_port_dir_t dir) +{ + if (dir == NRF_GPIO_PORT_DIR_OUTPUT) + { + nrf_gpio_word_byte_write(&NRF_GPIO->DIRSET, port, 0xFF); + } + else + { + nrf_gpio_range_cfg_input(port*8, (port+1)*8-1, NRF_GPIO_PIN_NOPULL); + } +} + +/** + * @brief Function for reading a GPIO port. + * + * @param port is the port to read. + * + * @return the input value on this port. + */ +static __INLINE uint8_t nrf_gpio_port_read(nrf_gpio_port_select_t port) +{ + return nrf_gpio_word_byte_read(&NRF_GPIO->IN, port); +} + +/** + * @brief Function for writing to a GPIO port. + * + * @param port is the port to write. + * + * @param value is the value to write to this port. + * + * @sa nrf_gpio_port_dir_set() + */ +static __INLINE void nrf_gpio_port_write(nrf_gpio_port_select_t port, uint8_t value) +{ + nrf_gpio_word_byte_write(&NRF_GPIO->OUT, port, value); +} + +/** + * @brief Function for setting individual pins on GPIO port. + * + * @param port is the port for which to set the pins. + * + * @param set_mask is a mask specifying which pins to set. A bit + * set to 1 indicates that the corresponding port pin shall be + * set. + * + * @sa nrf_gpio_port_dir_set() + */ +static __INLINE void nrf_gpio_port_set(nrf_gpio_port_select_t port, uint8_t set_mask) +{ + nrf_gpio_word_byte_write(&NRF_GPIO->OUTSET, port, set_mask); +} + +/** + * @brief Function for clearing individual pins on GPIO port. + * + * @param port is the port for which to clear the pins. + * + * @param clr_mask is a mask specifying which pins to clear. A bit + * set to 1 indicates that the corresponding port pin shall be + * cleared. + * + * @sa nrf_gpio_port_dir_set() + */ +static __INLINE void nrf_gpio_port_clear(nrf_gpio_port_select_t port, uint8_t clr_mask) +{ + nrf_gpio_word_byte_write(&NRF_GPIO->OUTCLR, port, clr_mask); +} + +/** @} */ + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nrf_gpiote.h Tue Dec 08 11:58:59 2015 +0000 @@ -0,0 +1,153 @@ +/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved. + * + * The information contained herein is property of Nordic Semiconductor ASA. + * Terms and conditions of usage are described in detail in NORDIC + * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. + * + * Licensees are granted free, non-transferable use of the information. NO + * WARRANTY of ANY KIND is provided. This heading must NOT be removed from + * the file. + * + */ +#ifndef NRF_GPIOTE_H__ +#define NRF_GPIOTE_H__ + +#include "nrf.h" + +/** +* @defgroup nrf_gpiote GPIOTE abstraction +* @{ +* @ingroup nrf_drivers +* @brief GPIOTE abstraction for configuration of channels. +*/ + + + /** + * @enum nrf_gpiote_polarity_t + * @brief Polarity for GPIOTE channel enumerator. + */ +typedef enum +{ + NRF_GPIOTE_POLARITY_LOTOHI = GPIOTE_CONFIG_POLARITY_LoToHi, ///< Low to high + NRF_GPIOTE_POLARITY_HITOLO = GPIOTE_CONFIG_POLARITY_HiToLo, ///< High to low + NRF_GPIOTE_POLARITY_TOGGLE = GPIOTE_CONFIG_POLARITY_Toggle ///< Toggle +} nrf_gpiote_polarity_t; + + + /** + * @enum nrf_gpiote_outinit_t + * @brief Initial output value for GPIOTE channel enumerator. + */ +typedef enum +{ + NRF_GPIOTE_INITIAL_VALUE_LOW = GPIOTE_CONFIG_OUTINIT_Low, ///< Low to high + NRF_GPIOTE_INITIAL_VALUE_HIGH = GPIOTE_CONFIG_OUTINIT_High ///< High to low +} nrf_gpiote_outinit_t; + + +/** + * @brief Function for configuring GPIOTE channel as output, setting the properly desired output level. + * + * + * @param channel_number specifies the GPIOTE channel [0:3] to configure as an output channel. + * @param pin_number specifies the pin number [0:30] to use in the GPIOTE channel. + * @param polarity specifies the desired polarity in the output GPIOTE channel. + * @param initial_value specifies the initial value of the GPIOTE channel input after the channel configuration. + */ +static __INLINE void nrf_gpiote_task_config(uint32_t channel_number, uint32_t pin_number, nrf_gpiote_polarity_t polarity, nrf_gpiote_outinit_t initial_value) +{ + /* Check if the output desired is high or low */ + if (initial_value == NRF_GPIOTE_INITIAL_VALUE_LOW) + { + /* Workaround for the OUTINIT PAN. When nrf_gpiote_task_config() is called a glitch happens + on the GPIO if the GPIO in question is already assigned to GPIOTE and the pin is in the + correct state in GPIOTE but not in the OUT register. */ + NRF_GPIO->OUTCLR = (1 << pin_number); + + /* Configure channel to Pin31, not connected to the pin, and configure as a tasks that will set it to proper level */ + NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | + (31UL << GPIOTE_CONFIG_PSEL_Pos) | + (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos); + } + else + { + /* Workaround for the OUTINIT PAN. When nrf_gpiote_task_config() is called a glitch happens + on the GPIO if the GPIO in question is already assigned to GPIOTE and the pin is in the + correct state in GPIOTE but not in the OUT register. */ + NRF_GPIO->OUTSET = (1 << pin_number); + + /* Configure channel to Pin31, not connected to the pin, and configure as a tasks that will set it to proper level */ + NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | + (31UL << GPIOTE_CONFIG_PSEL_Pos) | + (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos); + } + + /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */ + __NOP(); + __NOP(); + __NOP(); + + /* Launch the task to take the GPIOTE channel output to the desired level */ + NRF_GPIOTE->TASKS_OUT[channel_number] = 1; + + + /* Finally configure the channel as the caller expects. If OUTINIT works, the channel is configured properly. + If it does not, the channel output inheritance sets the proper level. */ + NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | + ((uint32_t)pin_number << GPIOTE_CONFIG_PSEL_Pos) | + ((uint32_t)polarity << GPIOTE_CONFIG_POLARITY_Pos) | + ((uint32_t)initial_value << GPIOTE_CONFIG_OUTINIT_Pos); + + /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */ + __NOP(); + __NOP(); + __NOP(); +} + +/** + * @brief Function for configuring GPIOTE channel as input, automatically clearing an event that appears in some cases under configuration. + * + * Note that when configuring the channel as input an event might be triggered. Care of disabling interrupts + * for that channel is left to the user. + * + * @param channel_number specifies the GPIOTE channel [0:3] to configure as an input channel. + * @param pin_number specifies the pin number [0:30] to use in the GPIOTE channel. + * @param polarity specifies the desired polarity in the output GPIOTE channel. + */ +static __INLINE void nrf_gpiote_event_config(uint32_t channel_number, uint32_t pin_number, nrf_gpiote_polarity_t polarity) +{ + /* Configure the channel as the caller expects */ + NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) | + ((uint32_t)pin_number << GPIOTE_CONFIG_PSEL_Pos) | + ((uint32_t)polarity << GPIOTE_CONFIG_POLARITY_Pos); + + /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */ + __NOP(); + __NOP(); + __NOP(); + + /* Clear the event that appears in some cases */ + NRF_GPIOTE->EVENTS_IN[channel_number] = 0; +} + + +/** + * @brief Function for unconfiguring GPIOTE channel. + * + * + * Note that when unconfiguring the channel, the pin is configured as GPIO PIN_CNF configuration. + * + * @param channel_number specifies the GPIOTE channel [0:3] to unconfigure. + */ +static __INLINE void nrf_gpiote_unconfig(uint32_t channel_number) +{ + /* Unonfigure the channel as the caller expects */ + NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Disabled << GPIOTE_CONFIG_MODE_Pos) | + (31UL << GPIOTE_CONFIG_PSEL_Pos) | + (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos); +} + + +/** @} */ + +#endif