diff --git a/BluePillExtender/.gitignore b/BluePillExtender/.gitignore new file mode 100644 index 0000000..905ba1e --- /dev/null +++ b/BluePillExtender/.gitignore @@ -0,0 +1,6 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch +extensions.json diff --git a/BluePillExtender/extra_script.py b/BluePillExtender/extra_script.py new file mode 100644 index 0000000..da5295d --- /dev/null +++ b/BluePillExtender/extra_script.py @@ -0,0 +1,11 @@ +Import("env") + +env.Append( + # Use the semihosted version of the syscalls + LINKFLAGS=[ + "--specs=rdimon.specs" + ], + LIBS=[ + "rdimon", + ], +) \ No newline at end of file diff --git a/BluePillExtender/include/README b/BluePillExtender/include/README new file mode 100644 index 0000000..49819c0 --- /dev/null +++ b/BluePillExtender/include/README @@ -0,0 +1,37 @@ + +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 convention is to give header files names that end with `.h'. + +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/BluePillExtender/lib/README b/BluePillExtender/lib/README new file mode 100644 index 0000000..9379397 --- /dev/null +++ b/BluePillExtender/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 the executable file. + +The source code of each library should be placed in a separate directory +("lib/your_library_name/[Code]"). + +For example, see the structure of the following example libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional. for 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 + +Example contents of `src/main.c` using Foo and Bar: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +The PlatformIO Library Dependency Finder will find automatically dependent +libraries by scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/BluePillExtender/platformio.ini b/BluePillExtender/platformio.ini new file mode 100644 index 0000000..aebc444 --- /dev/null +++ b/BluePillExtender/platformio.ini @@ -0,0 +1,53 @@ +; 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:bluepill_f103c8] +platform = ststm32 +board = bluepill_f103c8 +framework = arduino +upload_protocol = stlink + +; Add The following lines of code to your project's platformio.ini file. +upload_flags = -c set CPUTAPID 0 ; Allow Original and Clone STM32 to be detected by OpenOCD debugger. +debug_build_flags = -O0 -ggdb3 ; Apply no optimization to the code written. +;debug_init_break = tbreak Reset_Handler ; Uncomment to activate: Adds a break point in the reset handler. + + +; ============ Enable Arm Semihosting in debugger to show logs ============= + +; Add The following code lines to enable semihosting feature. +; To disable semihosting please comment all of the following code lines by adding semicolon ";" before each one: + +build_unflags = + --specs=nosys.specs + -lnosys + +extra_scripts = extra_script.py ; The "extra_script.py" file must be located in the main project folder + +debug_extra_cmds = + monitor arm semihosting enable + monitor arm semihosting_fileio enable + +test_testing_command = + ${platformio.packages_dir}/tool-openocd/bin/openocd + -s + ${platformio.packages_dir}/tool-openocd + -f + openocd/scripts/board/stlink.cfg + -c + init + -c + arm semihosting enable + -c + reset run + +; debug_tool = custom +; debug_port = :3333 +; =========================================================================== \ No newline at end of file diff --git a/BluePillExtender/src/main.cpp b/BluePillExtender/src/main.cpp new file mode 100644 index 0000000..7e1dada --- /dev/null +++ b/BluePillExtender/src/main.cpp @@ -0,0 +1,160 @@ +#include + +// This file is to be loaded onto an STM32F103C8 as a simple IO extender to the ESP module. +// Communication between ESP and STM32 is using the I2C bus, so only two wires needed. +// BluePill +// - I2C1: SDA – PB7 or PB9 | SCL – PB6 or PB8 +// - I2C2: SDA – PB11 | SCL – PB10. +// Configure it before upload it. +// ESP I2C can be configured but they are on GPIO-4 and GPIO-5 by default. + +#include + +#define I2C_ADDRESS 0x7f +#define I2C_INTERFACE 1 + +#if I2C_INTERFACE == 1 + #define I2C_SCL_PIN PB6 // PB8 + #define I2C_SDA_PIN PB7 // PB9 +#else + #define I2C_SCL_PIN PB10 + #define I2C_SDA_PIN PB11 +#endif + + +#define I2C_MSG_IN_SIZE 4 +#define I2C_MSG_OUT_SIZE 4 + +#define CMD_DIGITAL_WRITE 1 +#define CMD_DIGITAL_READ 2 +#define CMD_ANALOG_WRITE 3 +#define CMD_ANALOG_READ 4 +// #define CMD_CONFIG_PIN 5 +// #define CFG_PIN_DIGITALIN 1 +// #define CFG_PIN_DIGITALOUT 2 +// #define CFG_PIN_ANALOGIN 3 + +// Tabela de mapeamento: Índice (Byte recebido) -> Pino Físico STM32 +// Você pode alterar a ordem ou os pinos conforme sua necessidade física. +const uint32_t pinMap[] = { + // --- GROUP 1: PURE DIGITAL (GPIO) --- + // digitalRead() and digitalWrite() only. + // Most are 5V tolerant (FT). + PA8, // ID 0 + PA9, // ID 1 (Default TX1) + PA10, // ID 2 (Default RX1) + PB5, // ID 3 + // PB6, // ID 4 (I2C1 SCL / TIM4_CH1) + // PB7, // ID 5 (I2C1 SDA / TIM4_CH2) + PB8, // ID 6 (I2C1 SCL / TIM4_CH3 / CAN RX) + PB9, // ID 7 (I2C1 SDA / TIM4_CH4 / CAN TX) + PB10, // ID 8 (I2C2 SCL / UART3 TX) + PB11, // ID 9 (I2C2 SDA / UART3 RX) + PB12, // ID 10 (SPI2 NSS) + PB13, // ID 11 (SPI2 SCK) + PB14, // ID 12 (SPI2 MISO) + PB15, // ID 13 (SPI2 MOSI) + + // --- GROUP 2: SPECIAL PINS (Use with caution) --- + PA15, // ID 14 (JTAG - OK if JTAG is disabled/remapped) + PB3, // ID 15 (JTAG - OK if JTAG is disabled/remapped) + PB4, // ID 16 (JTAG - OK if JTAG is disabled/remapped) + PC13, // ID 17 (Onboard LED - Inverted Logic) + // PC14, // ID 18 (32k Oscillator - Use with caution) + // PC15, // ID 19 (32k Oscillator - Use with caution) + + // --- GROUP 3: ANALOG INPUTS (ADC1) --- + // These pins accept analogRead() as well as digitalRead()/digitalWrite() + PA0, // ID 20 + PA1, // ID 21 + PA2, // ID 22 + PA3, // ID 23 + PA4, // ID 24 + PA5, // ID 25 + PA6, // ID 26 + PA7, // ID 27 + PB0, // ID 28 + PB1, // ID 29 +}; + +volatile uint8_t sendBuffer[I2C_MSG_OUT_SIZE]; + +void receiveEvent(int); +void clearSendBuffer(); +void requestEvent(); + +// Semihosting +// extern "C" void initialise_monitor_handles(void); + +void setup() +{ + // Semihosting + // initialise_monitor_handles(); /* This Function MUST come before the first printf() */ + for (int i = 0; i < 30; i++){ + if (i >=20) + pinMode(pinMap[i], INPUT_ANALOG); + else + pinMode(pinMap[i], INPUT_PULLUP); + } + + Wire.setSCL(I2C_SCL_PIN); + Wire.setSDA(I2C_SDA_PIN); + Wire.begin(I2C_ADDRESS); + Wire.onReceive(receiveEvent); + Wire.onRequest(requestEvent); +} + +void loop() {} + +void receiveEvent(int count) +{ + if (count == I2C_MSG_IN_SIZE) + { + byte cmd = Wire.read(); + byte portIndex = Wire.read(); + int value = Wire.read(); + value += Wire.read()*256; + + if (portIndex >= 29) return; + uint32_t port = pinMap[portIndex]; + + switch(cmd) + { + + case CMD_DIGITAL_WRITE: + pinMode(port, OUTPUT); + digitalWrite(port,value); + break; + + case CMD_DIGITAL_READ: + pinMode(port, INPUT_PULLUP); + clearSendBuffer(); + sendBuffer[0] = digitalRead(port); + break; + + case CMD_ANALOG_WRITE: + pinMode(port, OUTPUT); + analogWrite(port,value); + break; + + case CMD_ANALOG_READ: + if (portIndex < 20) return; + clearSendBuffer(); + int valueRead = analogRead(port); + sendBuffer[0] = valueRead & 0xff; + sendBuffer[1] = valueRead >> 8; + break; + } + } +} + +void clearSendBuffer() +{ + for(byte x=0; x < sizeof(sendBuffer); x++) + sendBuffer[x]=0; +} + +void requestEvent() +{ + Wire.write((const uint8_t*)sendBuffer,sizeof(sendBuffer)); +} diff --git a/BluePillExtender/test/README b/BluePillExtender/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/BluePillExtender/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner 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 PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html diff --git a/README.md b/README.md index 14dac6c..37e04dd 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,44 @@ # ESPEasySlaves -Arduino (AVR/ATTiny) based slave projects for ESP Easy + +Arduino (AVR/ATTiny/STM32) based slave projects for ESP Easy + +## STM32 - Bluepill - STM32F103c8 + +This firmware turns the Bluepill into an I/O extender via I2C. + +### I2C Configuration +* **Address:** `0x7f` +* **Pins:** SCL=`PB6`, SDA=`PB7` + +### Pin Mapping + +| Index | STM32 Pin | Type | Notes | +| :---: | :--- | :--- | :--- | +| 0 | PA8 | Digital | | +| 1 | PA9 | Digital | | +| 2 | PA10 | Digital | | +| 3 | PB5 | Digital | | +| 4 | PB8 | Digital | | +| 5 | PB9 | Digital | | +| 6 | PB10 | Digital | | +| 7 | PB11 | Digital | | +| 8 | PB12 | Digital | | +| 9 | PB13 | Digital | | +| 10 | PB14 | Digital | | +| 11 | PB15 | Digital | | +| 12 | PA15 | Digital | JTAG | +| 13 | PB3 | Digital | JTAG | +| 14 | PB4 | Digital | JTAG | +| 15 | PC13 | Digital | LED Onboard | +| 16 | PA0 | Digital | *Restricted to Digital (see note)* | +| 17 | PA1 | Digital | *Restricted to Digital (see note)* | +| 18 | PA2 | Digital | *Restricted to Digital (see note)* | +| 19 | PA3 | Digital | *Restricted to Digital (see note)* | +| 20 | PA4 | Analog/Digital | | +| 21 | PA5 | Analog/Digital | | +| 22 | PA6 | Analog/Digital | | +| 23 | PA7 | Analog/Digital | | +| 24 | PB0 | Analog/Digital | | +| 25 | PB1 | Analog/Digital | | + +> **Note:** Due to the current firmware logic, the `CMD_ANALOG_READ` command is only processed for indices >= 20. Therefore, PA0-PA3 work only as Digital I/O in this mapping.