From 57d11c5b97227ff954a04ad26cda8fe61bfe7241 Mon Sep 17 00:00:00 2001 From: Vsevolod Merenkov Date: Sun, 29 Mar 2020 20:56:43 +0300 Subject: [PATCH] Added i2c bridge sketch --- .../src/pP_config.cpp | 2 +- .../Pyr0_Piezo_Sensor_v2.x.x/src/pP_i2c.cpp | 45 +++-- .../Pyr0_Piezo_i2c_Bridge/.clang-format | 3 + .../Pyr0_Piezo_i2c_Bridge/.gitignore | 7 + .../.vscode/extensions.json | 7 + .../Pyr0_Piezo_i2c_Bridge/include/README | 39 ++++ .../Pyr0_Piezo_i2c_Bridge/lib/README | 46 +++++ .../Pyr0_Piezo_i2c_Bridge/platformio.ini | 14 ++ .../Pyr0_Piezo_i2c_Bridge/src/i2c.cpp | 73 +++++++ .../Pyr0_Piezo_i2c_Bridge/src/i2c.h | 49 +++++ .../Pyr0_Piezo_i2c_Bridge/src/main.cpp | 21 ++ .../Pyr0_Piezo_i2c_Bridge/src/pP_serial.h | 191 ++++++++++++++++++ .../Pyr0_Piezo_i2c_Bridge/test/README | 11 + 13 files changed, 485 insertions(+), 23 deletions(-) create mode 100644 firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.clang-format create mode 100644 firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.gitignore create mode 100644 firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.vscode/extensions.json create mode 100644 firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/include/README create mode 100644 firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/lib/README create mode 100644 firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/platformio.ini create mode 100644 firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/i2c.cpp create mode 100644 firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/i2c.h create mode 100644 firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/main.cpp create mode 100644 firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/pP_serial.h create mode 100644 firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/test/README diff --git a/firmware/AVR-Source/Pyr0_Piezo_Sensor_v2.x.x/src/pP_config.cpp b/firmware/AVR-Source/Pyr0_Piezo_Sensor_v2.x.x/src/pP_config.cpp index 02af5af..3f0cbb2 100644 --- a/firmware/AVR-Source/Pyr0_Piezo_Sensor_v2.x.x/src/pP_config.cpp +++ b/firmware/AVR-Source/Pyr0_Piezo_Sensor_v2.x.x/src/pP_config.cpp @@ -12,7 +12,7 @@ int LOGIC = LOGIC_DEFAULT; int PZDET = PZDET_DEFAULT; int Debug = 0; long voltMeterConstant = VM_CONST_DEFAULT; -uint8_t pP_i2c_address = 0x80; +uint8_t pP_i2c_address = 0x10; /*------------------------------------------------*/ void eraseEEPROM() { diff --git a/firmware/AVR-Source/Pyr0_Piezo_Sensor_v2.x.x/src/pP_i2c.cpp b/firmware/AVR-Source/Pyr0_Piezo_Sensor_v2.x.x/src/pP_i2c.cpp index c2796cc..5d5d40f 100644 --- a/firmware/AVR-Source/Pyr0_Piezo_Sensor_v2.x.x/src/pP_i2c.cpp +++ b/firmware/AVR-Source/Pyr0_Piezo_Sensor_v2.x.x/src/pP_i2c.cpp @@ -7,10 +7,16 @@ uint8_t command; uint16_t value; -void i2cInit() { - Wire.begin(pP_i2c_address); - Wire.onRequest(i2cReply); - Wire.onReceive(i2cInput); +void i2cWrite(int data) { + Wire.write(data >> 8); + Wire.write(data); +} + +void i2cWrite(long data) { + Wire.write(data >> 24); + Wire.write(data >> 16); + Wire.write(data >> 8); + Wire.write(data); } void i2cReportConfig() { @@ -33,25 +39,9 @@ void i2cReportState() { i2cWrite(PZ_STATE); } -void i2cWrite(int data) { - Wire.write(data >> 24); - Wire.write(data >> 16); - Wire.write(data >> 8); - Wire.write(data); -} - -void i2cWrite(long data) { - Wire.write(data >> 56); - Wire.write(data >> 48); - Wire.write(data >> 40); - Wire.write(data >> 32); - Wire.write(data >> 24); - Wire.write(data >> 16); - Wire.write(data >> 8); - Wire.write(data); -} - void i2cReply() { + Serial.print("Requested "); + Serial.println(command); switch (command) { case CMD_CONFIG: case CMD_ERASE: @@ -79,6 +69,11 @@ void i2cInput(int bytesReceived) { } } + Serial.print("Command "); + Serial.print(command); + Serial.print(" "); + Serial.println(value); + // Parse commands and apply changes or actions switch (command) { case CMD_GAIN_F: @@ -119,3 +114,9 @@ void i2cInput(int bytesReceived) { return; } } + +void i2cInit() { + Wire.begin(pP_i2c_address); + Wire.onRequest(i2cReply); + Wire.onReceive(i2cInput); +} diff --git a/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.clang-format b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.clang-format new file mode 100644 index 0000000..fab33b7 --- /dev/null +++ b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.clang-format @@ -0,0 +1,3 @@ +BasedOnStyle: LLVM +ColumnLimit: 200 +AllowShortFunctionsOnASingleLine: false \ No newline at end of file diff --git a/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.gitignore b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.gitignore new file mode 100644 index 0000000..8501923 --- /dev/null +++ b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.gitignore @@ -0,0 +1,7 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch +.vscode/settings.json +.travis.yml \ No newline at end of file diff --git a/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.vscode/extensions.json b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.vscode/extensions.json new file mode 100644 index 0000000..e80666b --- /dev/null +++ b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ] +} diff --git a/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/include/README b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/lib/README b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/platformio.ini b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/platformio.ini new file mode 100644 index 0000000..ea23b77 --- /dev/null +++ b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/platformio.ini @@ -0,0 +1,14 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:uno] +platform = atmelavr +board = uno +framework = arduino diff --git a/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/i2c.cpp b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/i2c.cpp new file mode 100644 index 0000000..a9605fa --- /dev/null +++ b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/i2c.cpp @@ -0,0 +1,73 @@ +#include "i2c.h" +#include "Wire.h" +#include "Arduino.h" + +uint16_t read16() { + return Wire.read() << 8 | Wire.read(); +} + +uint32_t read32() { + return (uint32_t)Wire.read() << 24 | (uint32_t)Wire.read() << 16 | Wire.read() << 8 | Wire.read(); +} + +void write(uint8_t cmd) { + Wire.beginTransmission(ADDRESS); + Wire.write(cmd); + Wire.endTransmission(); +} + +void write(uint8_t cmd, uint16_t value) { + Wire.beginTransmission(ADDRESS); + Wire.write(cmd); + Wire.write(value >> 8); + Wire.write(value); + Wire.endTransmission(); +} + +void write(uint8_t cmd, uint32_t value) { + Wire.beginTransmission(ADDRESS); + Wire.write(cmd); + Wire.write(value >> 24); + Wire.write(value >> 16); + Wire.write(value >> 8); + Wire.write(value); + Wire.endTransmission(); +} + +config_t requestConfig() { + Wire.beginTransmission(ADDRESS); + Wire.write(CMD_CONFIG); + Wire.endTransmission(); + + uint8_t bytes = Wire.requestFrom(ADDRESS, 255); + Serial.println(bytes); + + config_t config; + config.GAIN_FACTOR = read16(); + config.followerThrs = read16(); + config.compThrs = read16(); + config.LOOP_DUR = read16(); + config.TRG_DUR = read16(); + config.Hyst = read16(); + config.LOGIC = read16(); + config.PZDET = read16(); + config.voltMeterConstant = read32(); + config.version = Wire.readString(); + + return config; +} + +state_t requestState() { + Wire.beginTransmission(ADDRESS); + Wire.write(CMD_STATE); + Wire.endTransmission(); + + uint8_t bytes = Wire.requestFrom(ADDRESS, 10); + + state_t state; + state.Vin = read16(); + state.VComp = read16(); + state.VFol = read16(); + state.ERR_STATE = read16(); + state.PZ_STATE = read16(); +} \ No newline at end of file diff --git a/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/i2c.h b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/i2c.h new file mode 100644 index 0000000..13ab362 --- /dev/null +++ b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/i2c.h @@ -0,0 +1,49 @@ +#ifndef I2C +#define I2C + +#define ADDRESS 0x10 + +#define CMD_GAIN_F 0x00 +#define CMD_VFOL 0x01 +#define CMD_VCOMP 0x02 +#define CMD_LOOP_D 0x03 +#define CMD_TRG_D 0x04 +#define CMD_HYST 0x05 +#define CMD_LOGIC 0x06 +#define CMD_PZDET 0x07 +#define CMD_CONST 0x08 +#define CMD_CONFIG 0x09 +#define CMD_ERASE 0x0a +#define CMD_STATE 0x0b + +#include "WString.h" + +typedef struct { + uint16_t GAIN_FACTOR; + uint16_t followerThrs; + uint16_t compThrs; + uint16_t LOOP_DUR; + uint16_t TRG_DUR; + uint16_t Hyst; + uint16_t LOGIC; + uint16_t PZDET; + uint32_t voltMeterConstant; + String version; +} config_t; + +typedef struct { + uint16_t Vin; + uint16_t VComp; + uint16_t VFol; + uint16_t ERR_STATE; + uint16_t PZ_STATE; +} state_t; + +void write(uint8_t cmd); +void write(uint8_t cmd, uint16_t value); +void write(uint8_t cmd, uint32_t value); + +config_t requestConfig(); +state_t requestState(); + +#endif \ No newline at end of file diff --git a/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/main.cpp b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/main.cpp new file mode 100644 index 0000000..58c41ce --- /dev/null +++ b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/main.cpp @@ -0,0 +1,21 @@ +#define ARDUINO_AVR_ATmega328PB + +#include +#include + +#include "pP_serial.h" + +void setup() { + Serial.begin(9600); + Serial.println("Initializing Pyr0-Piezo i2c Bridge..."); + + Wire.begin(); +} + +void loop() { + serialInput(); + + if (serialIncoming) { + updateParams(); + } +} \ No newline at end of file diff --git a/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/pP_serial.h b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/pP_serial.h new file mode 100644 index 0000000..24f118f --- /dev/null +++ b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/src/pP_serial.h @@ -0,0 +1,191 @@ +#include "i2c.h" +#include "stdint.h" + +#define buffSize 40 +bool serialIncoming = false; +uint8_t bytesRecvd = 0; +char inputBuffer[buffSize]; +char serialMessageIn[buffSize] = {0}; +uint32_t serialLong = 0; + +void parseData() { + + // split the data into its parts + + char *strtokIndx; // this is used by strtok() as an index + + strtokIndx = strtok(inputBuffer, " "); // get the first part - the string + strcpy(serialMessageIn, strtokIndx); // copy it to serialMessageIn + + strtokIndx = strtok(NULL, " "); // this continues where the previous call left off + serialLong = atol(strtokIndx); // convert this part to an integer +} +/*------------------------------------------------*/ + +void identifyMarkers() { + + char x = Serial.read(); + + if (x == '\n' || x == '\r') { + serialIncoming = true; + inputBuffer[bytesRecvd] = 0; + parseData(); + bytesRecvd = 0; + } else { + inputBuffer[bytesRecvd] = x; + bytesRecvd++; + if (bytesRecvd == buffSize) { + bytesRecvd = buffSize - 1; + } + } +} + +/*------------------------------------------------*/ + +void serialPrintConfig() { + config_t config = requestConfig(); + + Serial.print("GAIN_F "); + Serial.print(config.GAIN_FACTOR); + switch (config.GAIN_FACTOR) { + case 0: + Serial.println(" 3x"); + break; + case 1: + Serial.println(" 3.5x"); + break; + case 2: + Serial.println(" 4.33x"); + break; + case 3: + Serial.println(" 6x"); + break; + case 4: + Serial.println(" 11x"); + break; + default: + Serial.println(" INVALID"); + break; + } + + Serial.print("VFOL "); + Serial.println(config.followerThrs); + + Serial.print("VCOMP "); + Serial.println(config.compThrs); + + Serial.print("LOOP_D "); + Serial.println(config.LOOP_DUR); + + Serial.print("TRG_D "); + Serial.println(config.TRG_DUR); + + Serial.print("HYST "); + Serial.println(config.Hyst); + + Serial.print("LOGIC "); + Serial.println(config.LOGIC); + + Serial.print("PZDET "); + Serial.println(config.PZDET); + + Serial.print("VM_CONST "); + Serial.println(config.voltMeterConstant); + + Serial.print("Firmware Version "); + Serial.println(config.version); +} + +void serialPrintState() { + state_t state = requestState(); + + Serial.print("{"); + + Serial.print("\"Vcc\":"); + Serial.print(state.Vin); + Serial.print(","); + + Serial.print("\"VComp\":"); + Serial.print((uint32_t)state.VComp * state.Vin / 1023); + Serial.print(","); + + Serial.print("\"VFol\":"); + Serial.print((uint32_t)state.VFol * state.Vin / 1023); + Serial.print(","); + + Serial.print("\"Err\":"); + Serial.print(state.ERR_STATE); + Serial.print(","); + + Serial.print("\"PzCon\":"); + Serial.print(state.PZ_STATE); + + Serial.println("}"); +} + +void updateParams() { + serialIncoming = false; + if (strcmp(serialMessageIn, "GAIN_F") == 0) { + write(CMD_GAIN_F, (uint16_t)serialLong); + } else if (strcmp(serialMessageIn, "VFOL") == 0) { + write(CMD_VFOL, (uint16_t)serialLong); + } else if (strcmp(serialMessageIn, "VCOMP") == 0) { + write(CMD_VCOMP, (uint16_t)serialLong); + } else if (strcmp(serialMessageIn, "LOOP_D") == 0) { + write(CMD_LOOP_D, (uint16_t)serialLong); + } else if (strcmp(serialMessageIn, "TRG_D") == 0) { + write(CMD_TRG_D, (uint16_t)serialLong); + } else if (strcmp(serialMessageIn, "HYST") == 0) { + write(CMD_HYST, (uint16_t)serialLong); + } else if (strcmp(serialMessageIn, "LOGIC") == 0) { + write(CMD_LOGIC, (uint16_t)serialLong); + } else if (strcmp(serialMessageIn, "PZDET") == 0) { + write(CMD_PZDET, (uint16_t)serialLong); + } else if (strcmp(serialMessageIn, "CONST") == 0) { + write(CMD_CONST, serialLong); + } else if (strcmp(serialMessageIn, "CONFIG") == 0) { + serialPrintConfig(); + } else if (strcmp(serialMessageIn, "ERASE") == 0) { + write(CMD_ERASE); + serialPrintConfig(); + } else if (strcmp(serialMessageIn, "STATE") == 0) { + serialPrintState(); + } else if (strcmp(serialMessageIn, "HELP") == 0) { +#if defined(ARDUINO_AVR_ATmega328PB) + Serial.println("To change gain factor: GAIN_F [integer for gain state - see note*]"); + Serial.println("To change voltage follower voltage (low threshold): VFOL [float value]"); + Serial.println("To change comparator voltage (high threshold): VCOMP [float value]"); + Serial.println("To change main loop period: LOOP_D [integer for milliseconds]"); + Serial.println("To change trigger active duration: TRG_D [integer for milliseconds]"); + Serial.println("To change the output logic: LOGIC [0|1]"); + Serial.println(" (0 for active low, 1 for active high)"); + Serial.println("To enable piezo plugged detection: PZDET [0|1]"); + Serial.println(" (0 for disabled, 1 for enabled)"); + Serial.println("To change ADC hysteresis value: HYST [integer in millivolts]"); + Serial.println("To enable or disable debug output: DEBUG [0|1]"); + Serial.println("To print current config: CONFIG"); + Serial.println("To set config to defaults: ERASE"); + Serial.println("To print current state: STATE"); + Serial.println(""); + Serial.println("Commands are entered in this format:"); + Serial.println("CMD VAL"); + Serial.println("Commands are confirmed with Enter key"); + Serial.println(""); + Serial.println("Examples:"); + Serial.println("GAIN_F 3 <~ set gain factor to index 3 (6x)"); + Serial.println("VFOL 2350 <~ set the vref floor to 2.35V"); +#else + Serial.println("Check docs.pyroballpcbs.com/config"); +#endif // defined(ARDUINO_AVR_ATmega328PB) + } + parseData(); +} + +void serialInput() { + // receive data from Serial and save it into inputBuffer + if (Serial.available() > 0) { + + // the order of these IF clauses is significant + identifyMarkers(); + } +} diff --git a/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/test/README b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/test/README new file mode 100644 index 0000000..df5066e --- /dev/null +++ b/firmware/AVR-Source/Pyr0_Piezo_i2c_Bridge/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html