Ajoute la liaison TMS320 (simulee), l'IHM OLED et la LED de statut
Protocole ASCII type NMEA ($T/$C avec checksum) entre l'ESP32-C3 et le TMS320 (frequence/duty/tensions/courants/temperatures + commandes HT/PWM1/PWM2), avec simulateur local le temps que le firmware TMS320 existe. Driver SSD1322 repointe sur les GPIO du schema, dashboard texte 3 pages tournantes sur l'ecran ER-OLEDM032-1. LED RGB embarquee (GPIO8) clignotante 1 Hz vert 30% comme indicateur de vie. Serveur web laisse en stub (sera branche en STA sur le reseau local une fois l'OLED valide). Ajout de la documentation technique (schema, datasheets, protocole).
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,3 +3,5 @@
|
|||||||
.vscode/c_cpp_properties.json
|
.vscode/c_cpp_properties.json
|
||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
.vscode/ipch
|
.vscode/ipch
|
||||||
|
desktop.ini
|
||||||
|
_desktop.ini
|
||||||
|
|||||||
@ -0,0 +1,76 @@
|
|||||||
|
/***************************************************
|
||||||
|
//Web: http://www.buydisplay.com
|
||||||
|
EastRising Technology Co.,LTD
|
||||||
|
Examples for ER-OLEDM032-1
|
||||||
|
Display is Hardward SPI 4-Wire SPI Interface
|
||||||
|
Tested and worked with:
|
||||||
|
Works with Arduino 2.3.4 IDE
|
||||||
|
NOTE: test OK:ESP32-WROOM-32
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note:The module needs to be jumpered to an SPI interface. R19,R23 Short and R18,R20 Open
|
||||||
|
Unused signal pin Recommended to connect to GND
|
||||||
|
/* == Hardward SPI to ESP32 ==
|
||||||
|
OLED => ESP32
|
||||||
|
*1. GND -> GND
|
||||||
|
*2. VCC -> 3.3-5V
|
||||||
|
*4. SCL -> 18
|
||||||
|
*5. SDI -> 23
|
||||||
|
*7-13 -> GND
|
||||||
|
*14. DC -> 17
|
||||||
|
*15. RES -> 16
|
||||||
|
*16. CS -> 5
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include "er_oled.h"
|
||||||
|
|
||||||
|
//uint8_t oled_buf[OLED_Y_MAXPIXEL * OLED_X_MAXPIXEL/2];
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
Serial.print("OLED Example\n");
|
||||||
|
|
||||||
|
/* display an image of bitmap matrix */
|
||||||
|
er_oled_begin();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
er_oled_clear();
|
||||||
|
er_oled_bitmap_gray(PIC1);
|
||||||
|
delay(3000);
|
||||||
|
|
||||||
|
er_oled_clear();
|
||||||
|
er_oled_bitmap_gray(PIC2);
|
||||||
|
delay(3000);
|
||||||
|
|
||||||
|
er_oled_clear();
|
||||||
|
er_oled_bitmap_mono(PIC3);
|
||||||
|
delay(3000);
|
||||||
|
|
||||||
|
er_oled_clear();
|
||||||
|
er_oled_string(0, 0, "********************************",0);
|
||||||
|
er_oled_string(32, 16, "EastRising Technology", 0);
|
||||||
|
er_oled_string(40, 32, "www.buydisplay.com", 1);
|
||||||
|
er_oled_string(0, 48, "********************************",0);
|
||||||
|
uint8_t i;
|
||||||
|
for(i=0;i<=48;i++)
|
||||||
|
{
|
||||||
|
command(0xa1); //start line
|
||||||
|
data(i);
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
for(i=48;i>0;i--)
|
||||||
|
{
|
||||||
|
command(0xa1); //start line
|
||||||
|
data(i);
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
command(0xa1); //start line
|
||||||
|
data(0);
|
||||||
|
}
|
||||||
|
|
||||||
187
doc/ER-OLEDM032-1_ESP32_Tutorial/ER-OLEDM032-1/er_oled.cpp
Normal file
187
doc/ER-OLEDM032-1_ESP32_Tutorial/ER-OLEDM032-1/er_oled.cpp
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/***************************************************
|
||||||
|
//Web: http://www.buydisplay.com
|
||||||
|
EastRising Technology Co.,LTD
|
||||||
|
****************************************************/
|
||||||
|
#include <SPI.h>
|
||||||
|
#include "er_oled.h"
|
||||||
|
|
||||||
|
|
||||||
|
void command(uint8_t cmd)
|
||||||
|
{
|
||||||
|
digitalWrite(OLED_DC, LOW);
|
||||||
|
digitalWrite(OLED_CS, LOW);
|
||||||
|
SPI.transfer(cmd);
|
||||||
|
digitalWrite(OLED_CS, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void data(uint8_t dat)
|
||||||
|
{
|
||||||
|
digitalWrite(OLED_DC, HIGH);
|
||||||
|
digitalWrite(OLED_CS, LOW );
|
||||||
|
SPI.transfer(dat);
|
||||||
|
digitalWrite(OLED_CS, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void er_oled_begin()
|
||||||
|
{
|
||||||
|
pinMode(OLED_RST, OUTPUT);
|
||||||
|
pinMode(OLED_DC, OUTPUT);
|
||||||
|
pinMode(OLED_CS, OUTPUT);
|
||||||
|
SPI.begin();
|
||||||
|
|
||||||
|
SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0));
|
||||||
|
//SPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||||
|
|
||||||
|
digitalWrite(OLED_CS, LOW);
|
||||||
|
digitalWrite(OLED_RST, HIGH);
|
||||||
|
delay(10);
|
||||||
|
digitalWrite(OLED_RST, LOW);
|
||||||
|
delay(10);
|
||||||
|
digitalWrite(OLED_RST, HIGH);
|
||||||
|
|
||||||
|
|
||||||
|
command(0xFD); /*SET COMMAND LOCK*/
|
||||||
|
data(0x12); /* UNLOCK */
|
||||||
|
command(0xAE); /*DISPLAY OFF*/
|
||||||
|
command(0xB3);/*DISPLAYDIVIDE CLOCKRADIO/OSCILLATAR FREQUANCY*/
|
||||||
|
data(0x91); command(0xCA); /*multiplex ratio*/
|
||||||
|
data(0x3F); /*duty = 1/64*/
|
||||||
|
command(0xA2); /*set offset*/
|
||||||
|
data(0x00);
|
||||||
|
command(0xA1); /*start line*/
|
||||||
|
data(0x00);
|
||||||
|
command(0xA0); /*set remap*/
|
||||||
|
data(0x14);
|
||||||
|
data(0x11);
|
||||||
|
|
||||||
|
command(0xAB); /*funtion selection*/
|
||||||
|
data(0x01); /* selection external vdd */
|
||||||
|
command(0xB4); /* */
|
||||||
|
data(0xA0);
|
||||||
|
data(0xfd);
|
||||||
|
command(0xC1); /*set contrast current */
|
||||||
|
data(0x80);
|
||||||
|
command(0xC7); /*master contrast current control*/
|
||||||
|
data(0x0f);
|
||||||
|
|
||||||
|
command(0xB1); /*SET PHASE LENGTH*/
|
||||||
|
data(0xE2);
|
||||||
|
command(0xD1); /**/
|
||||||
|
data(0x82);
|
||||||
|
data(0x20);
|
||||||
|
command(0xBB); /*SET PRE-CHANGE VOLTAGE*/
|
||||||
|
data(0x1F);
|
||||||
|
command(0xB6); /*SET SECOND PRE-CHARGE PERIOD*/
|
||||||
|
data(0x08);
|
||||||
|
command(0xBE); /* SET VCOMH */
|
||||||
|
data(0x07);
|
||||||
|
command(0xA6); /*normal display*/
|
||||||
|
command(0xAF); /*display ON*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void er_oled_SetWindow(uint8_t Xstart, uint8_t Ystart, uint8_t Xend, uint8_t Yend)
|
||||||
|
{
|
||||||
|
command(0x15);
|
||||||
|
data(Xstart+0x1c);
|
||||||
|
data(Xend+0x1c);
|
||||||
|
command(0x75);
|
||||||
|
data(Ystart);
|
||||||
|
data(Yend);
|
||||||
|
command(0x5c);//write ram command
|
||||||
|
}
|
||||||
|
|
||||||
|
void er_oled_clear()
|
||||||
|
{int i,row;
|
||||||
|
command(0x15);
|
||||||
|
data(0x00); //col start
|
||||||
|
data(0x77); //col end
|
||||||
|
command(0x75);
|
||||||
|
data(0x00); //row start
|
||||||
|
data(0x7f); //row end
|
||||||
|
command(0x5c);
|
||||||
|
for (row = 0; row < 128; row++) {
|
||||||
|
for(i = 0; i< 240; i++ ) {
|
||||||
|
data(0x00);// write data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void er_oled_char(uint8_t x, uint8_t y, const char *acsii, uint8_t mode)
|
||||||
|
{ uint8_t i,str;uint16_t OffSet;
|
||||||
|
x=x/4;
|
||||||
|
OffSet = (*acsii - 32)*16;
|
||||||
|
er_oled_SetWindow(x, y, x+1, y+15);
|
||||||
|
for (i=0;i<16;i++)
|
||||||
|
{ str =pgm_read_byte(&AsciiLib[OffSet + i]);
|
||||||
|
if(mode) str=~str;
|
||||||
|
Data_processing (str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void er_oled_string(uint8_t x, uint8_t y, const char *pString, uint8_t Mode)
|
||||||
|
{
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
if (*pString == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
er_oled_char(x, y, pString,Mode);
|
||||||
|
x += 8;
|
||||||
|
pString += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Data_processing(uint8_t temp) //turns 1byte B/W data to 4 bye gray data with 8 Pixel
|
||||||
|
{uint8_t temp1,temp2;
|
||||||
|
|
||||||
|
if(temp&0x80)temp1=0xf0;
|
||||||
|
else temp1=0x00;
|
||||||
|
if(temp&0x40)temp2=0x0f;
|
||||||
|
else temp2=0x00;
|
||||||
|
temp1=temp1|temp2;
|
||||||
|
data(temp1); //Pixel1,Pixel2
|
||||||
|
if(temp&0x20)temp1=0xf0;
|
||||||
|
else temp1=0x00;
|
||||||
|
if(temp&0x10)temp2=0x0f;
|
||||||
|
else temp2=0x00;
|
||||||
|
temp1=temp1|temp2;
|
||||||
|
data(temp1); //Pixel3,Pixel4
|
||||||
|
if(temp&0x08)temp1=0xf0;
|
||||||
|
else temp1=0x00;
|
||||||
|
if(temp&0x04)temp2=0x0f;
|
||||||
|
else temp2=0x00;
|
||||||
|
temp1=temp1|temp2;
|
||||||
|
data(temp1); //Pixel5,Pixel6
|
||||||
|
if(temp&0x02)temp1=0xf0;
|
||||||
|
else temp1=0x00;
|
||||||
|
if(temp&0x01)temp2=0x0f;
|
||||||
|
else temp2=0x00;
|
||||||
|
temp1=temp1|temp2;
|
||||||
|
data(temp1); //Pixel7,Pixel8
|
||||||
|
}
|
||||||
|
|
||||||
|
void er_oled_bitmap_mono(const uint8_t * pBuf)
|
||||||
|
{ uint8_t row,col,dat;
|
||||||
|
er_oled_SetWindow(0, 0, 255/4, 63);
|
||||||
|
for (row = 0; row < 64; row++) {
|
||||||
|
for(col = 0;col<256/8; col++ ) {
|
||||||
|
dat=(pgm_read_byte(pBuf));
|
||||||
|
*pBuf++;
|
||||||
|
Data_processing(dat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void er_oled_bitmap_gray(const uint8_t * pBuf)
|
||||||
|
{ uint8_t row,col;
|
||||||
|
er_oled_SetWindow(0, 0, 255/4, 63);
|
||||||
|
for (row = 0; row < 64; row++) {
|
||||||
|
for(col = 0;col<128; col++ ) {
|
||||||
|
data(pgm_read_byte(pBuf));
|
||||||
|
* pBuf++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1295
doc/ER-OLEDM032-1_ESP32_Tutorial/ER-OLEDM032-1/er_oled.h
Normal file
1295
doc/ER-OLEDM032-1_ESP32_Tutorial/ER-OLEDM032-1/er_oled.h
Normal file
File diff suppressed because it is too large
Load Diff
BIN
doc/ER-OLEDM032-1_Series_Datasheet.pdf
Normal file
BIN
doc/ER-OLEDM032-1_Series_Datasheet.pdf
Normal file
Binary file not shown.
BIN
doc/Interfacing_ER-OLEDM032-1_to_Arduino.pdf
Normal file
BIN
doc/Interfacing_ER-OLEDM032-1_to_Arduino.pdf
Normal file
Binary file not shown.
BIN
doc/SSD1322.pdf
Normal file
BIN
doc/SSD1322.pdf
Normal file
Binary file not shown.
10
doc/parametre-liaisonUART-TMS320-ESP32.txt
Normal file
10
doc/parametre-liaisonUART-TMS320-ESP32.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Paramètre TMS320:
|
||||||
|
Fréquence, Duty cycle (a convertir en %) etage 1 etage 2
|
||||||
|
A partir de lectures ADC:
|
||||||
|
Tension entrée, courant d'entrée
|
||||||
|
Tension etage 1, courant shunt mosfet 1, température (NTC) etage1, tension étage 2, courant shunt mosfet 2, température etage2.
|
||||||
|
Courant sortie.
|
||||||
|
|
||||||
|
Commande: activer/desactiver. sortie HT
|
||||||
|
activer désactiver PWM1
|
||||||
|
activer/desactiver PWM2.
|
||||||
BIN
doc/schema-esp32.png
Normal file
BIN
doc/schema-esp32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
24
include/config.h
Normal file
24
include/config.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Liaison UART vers le TMS320
|
||||||
|
#define PIN_TMS_UART_TX 7
|
||||||
|
#define PIN_TMS_UART_RX 6
|
||||||
|
#define TMS_UART_BAUD 115200
|
||||||
|
|
||||||
|
// LED RGB embarquee (WS2812) de l'ESP32-C3-DevKitM-1
|
||||||
|
#define PIN_RGB_LED 8
|
||||||
|
|
||||||
|
// Ecran OLED ER-OLEDM032-1 (SSD1322, SPI 4 fils)
|
||||||
|
#define PIN_OLED_MOSI 5
|
||||||
|
#define PIN_OLED_CLK 4
|
||||||
|
#define PIN_OLED_CS 10
|
||||||
|
#define PIN_OLED_RST 3
|
||||||
|
#define PIN_OLED_DC 1
|
||||||
|
|
||||||
|
// Le firmware TMS320 n'est pas encore programme : on simule la telemetrie
|
||||||
|
// en local le temps que le hardware TMS320 tourne. Passer a false quand le
|
||||||
|
// TMS320 emet reellement des trames $T,...*XX sur l'UART.
|
||||||
|
#define TMS_DUMMY_MODE true
|
||||||
|
|
||||||
|
// WiFi/serveur web de l'IHM : a definir une fois l'affichage OLED valide
|
||||||
|
// (connexion STA au reseau local, SSID/mot de passe a fournir).
|
||||||
38
include/protocol.h
Normal file
38
include/protocol.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// Protocole ASCII de type NMEA entre l'ESP32-C3 et le TMS320.
|
||||||
|
//
|
||||||
|
// Telemetrie TMS320 -> ESP32, periodique :
|
||||||
|
// $T,FREQ1=100000,FREQ2=100000,DUTY1=45.2,DUTY2=50.0,VIN=400.5,IIN=1.20,
|
||||||
|
// V1=200.3,I1=2.50,T1=45.2,VOUT=200.1,I2=2.48,T2=44.8,IOUT=1.05*XX\n
|
||||||
|
//
|
||||||
|
// Commande ESP32 -> TMS320, a chaque changement (et rafraichissement
|
||||||
|
// periodique) :
|
||||||
|
// $C,HT=1,PWM1=1,PWM2=0*XX\n
|
||||||
|
//
|
||||||
|
// XX = XOR de tous les octets entre '$' et '*', en hexadecimal majuscule.
|
||||||
|
|
||||||
|
struct Telemetry {
|
||||||
|
float freq1 = 0; // Hz, frequence etage 1
|
||||||
|
float freq2 = 0; // Hz, frequence etage 2
|
||||||
|
float duty1 = 0; // %, duty cycle etage 1
|
||||||
|
float duty2 = 0; // %, duty cycle etage 2
|
||||||
|
float vin = 0; // V, tension entree
|
||||||
|
float iin = 0; // A, courant entree
|
||||||
|
float v1 = 0; // V, tension etage 1
|
||||||
|
float i1 = 0; // A, courant shunt mosfet 1
|
||||||
|
float t1 = 0; // C, temperature NTC etage 1
|
||||||
|
float vout = 0; // V, tension etage 2 (sortie boost)
|
||||||
|
float i2 = 0; // A, courant shunt mosfet 2
|
||||||
|
float t2 = 0; // C, temperature NTC etage 2
|
||||||
|
float iout = 0; // A, courant sortie
|
||||||
|
uint32_t lastUpdateMs = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CommandState {
|
||||||
|
bool ht = false; // sortie HT activee/desactivee
|
||||||
|
bool pwm1 = false; // PWM etage 1 activee/desactivee
|
||||||
|
bool pwm2 = false; // PWM etage 2 activee/desactivee
|
||||||
|
};
|
||||||
225
src/er_oled.cpp
Normal file
225
src/er_oled.cpp
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
// Adapte du tutoriel EastRising Technology (buydisplay.com) pour
|
||||||
|
// ER-OLEDM032-1 / SSD1322, repointe sur les broches SPI de l'ESP32-C3
|
||||||
|
// (config.h) et limite a l'affichage texte.
|
||||||
|
|
||||||
|
#include "er_oled.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
static const uint8_t AsciiLib[] PROGMEM = {
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* */
|
||||||
|
0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x18,0x18,0x00,0x00, /* ! */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x28,0x28,0x50,0x00,0x00,0x00,0x00,0x00,0x00, /* " */
|
||||||
|
0x00,0x00,0x00,0x14,0x14,0x7E,0x14,0x14,0x28,0x7E,0x28,0x28,0x28,0x00,0x00,0x00, /* # */
|
||||||
|
0x00,0x00,0x10,0x38,0x54,0x54,0x50,0x30,0x18,0x14,0x54,0x54,0x38,0x10,0x10,0x00, /* $ */
|
||||||
|
0x00,0x00,0x00,0x44,0xA4,0xA8,0xA8,0x50,0x14,0x2A,0x2A,0x4A,0x44,0x00,0x00,0x00, /* % */
|
||||||
|
0x00,0x00,0x00,0x20,0x50,0x50,0x50,0x7C,0xA8,0xA8,0x98,0x88,0x76,0x00,0x00,0x00, /* & */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x30,0x00,0x00,0x00,0x00,0x00,0x00, /* ' */
|
||||||
|
0x00,0x00,0x04,0x08,0x10,0x10,0x20,0x20,0x20,0x20,0x20,0x10,0x10,0x08,0x04,0x00, /* ( */
|
||||||
|
0x00,0x00,0x20,0x10,0x08,0x08,0x04,0x04,0x04,0x04,0x04,0x08,0x08,0x10,0x20,0x00, /* ) */
|
||||||
|
0x00,0x00,0x00,0x00,0x10,0x10,0xD6,0x38,0x38,0xD6,0x10,0x10,0x00,0x00,0x00,0x00, /* * */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0xFE,0x10,0x10,0x10,0x00,0x00,0x00,0x00, /* + */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x30,0x00,0x00,0x00,0x00,0x00,0x00, /* , */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* . */
|
||||||
|
0x00,0x00,0x02,0x04,0x04,0x04,0x08,0x08,0x10,0x10,0x10,0x20,0x20,0x40,0x40,0x00, /* / */
|
||||||
|
0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00,0x00, /* 0 */
|
||||||
|
0x00,0x00,0x00,0x10,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,0x00, /* 1 */
|
||||||
|
0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00,0x00, /* 2 */
|
||||||
|
0x00,0x00,0x00,0x3C,0x42,0x42,0x04,0x18,0x04,0x02,0x42,0x42,0x3C,0x00,0x00,0x00, /* 3 */
|
||||||
|
0x00,0x00,0x00,0x08,0x08,0x18,0x28,0x48,0x48,0x7E,0x08,0x08,0x1E,0x00,0x00,0x00, /* 4 */
|
||||||
|
0x00,0x00,0x00,0x7E,0x40,0x40,0x5C,0x62,0x02,0x02,0x42,0x42,0x3C,0x00,0x00,0x00, /* 5 */
|
||||||
|
0x00,0x00,0x00,0x1C,0x24,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x3C,0x00,0x00,0x00, /* 6 */
|
||||||
|
0x00,0x00,0x00,0x7E,0x44,0x44,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00, /* 7 */
|
||||||
|
0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x3C,0x24,0x42,0x42,0x42,0x3C,0x00,0x00,0x00, /* 8 */
|
||||||
|
0x00,0x00,0x00,0x38,0x44,0x42,0x42,0x46,0x3A,0x02,0x02,0x24,0x38,0x00,0x00,0x00, /* 9 */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, /* : */
|
||||||
|
0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10,0x00,0x00,0x00, /* ; */
|
||||||
|
0x00,0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00, /* < */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00, /* = */
|
||||||
|
0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00, /* > */
|
||||||
|
0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x02,0x04,0x08,0x08,0x00,0x18,0x18,0x00,0x00, /* ? */
|
||||||
|
0x00,0x00,0x00,0x38,0x44,0x9A,0xAA,0xAA,0xAA,0xAA,0xB4,0x42,0x3C,0x00,0x00,0x00, /* @ */
|
||||||
|
0x00,0x00,0x00,0x10,0x10,0x28,0x28,0x28,0x28,0x7C,0x44,0x44,0xEE,0x00,0x00,0x00, /* A */
|
||||||
|
0x00,0x00,0x00,0xFC,0x42,0x42,0x44,0x78,0x44,0x42,0x42,0x42,0xFC,0x00,0x00,0x00, /* B */
|
||||||
|
0x00,0x00,0x00,0x3E,0x42,0x82,0x80,0x80,0x80,0x80,0x82,0x44,0x38,0x00,0x00,0x00, /* C */
|
||||||
|
0x00,0x00,0x00,0xF8,0x44,0x42,0x42,0x42,0x42,0x42,0x42,0x44,0xF8,0x00,0x00,0x00, /* D */
|
||||||
|
0x00,0x00,0x00,0xFC,0x42,0x48,0x48,0x78,0x48,0x48,0x40,0x42,0xFC,0x00,0x00,0x00, /* E */
|
||||||
|
0x00,0x00,0x00,0xFC,0x42,0x48,0x48,0x78,0x48,0x48,0x40,0x40,0xE0,0x00,0x00,0x00, /* F */
|
||||||
|
0x00,0x00,0x00,0x3C,0x44,0x84,0x80,0x80,0x80,0x8E,0x84,0x44,0x38,0x00,0x00,0x00, /* G */
|
||||||
|
0x00,0x00,0x00,0xEE,0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44,0xEE,0x00,0x00,0x00, /* H */
|
||||||
|
0x00,0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,0x00, /* I */
|
||||||
|
0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x88,0xF0,0x00,0x00, /* J */
|
||||||
|
0x00,0x00,0x00,0xEE,0x44,0x48,0x50,0x70,0x50,0x48,0x48,0x44,0xEE,0x00,0x00,0x00, /* K */
|
||||||
|
0x00,0x00,0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x42,0xFE,0x00,0x00,0x00, /* L */
|
||||||
|
0x00,0x00,0x00,0xEE,0x6C,0x6C,0x6C,0x54,0x54,0x54,0x54,0x54,0xD6,0x00,0x00,0x00, /* M */
|
||||||
|
0x00,0x00,0x00,0xEE,0x64,0x64,0x54,0x54,0x54,0x4C,0x4C,0x4C,0xE4,0x00,0x00,0x00, /* N */
|
||||||
|
0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00,0x00,0x00, /* O */
|
||||||
|
0x00,0x00,0x00,0xFC,0x42,0x42,0x42,0x7C,0x40,0x40,0x40,0x40,0xE0,0x00,0x00,0x00, /* P */
|
||||||
|
0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0xB2,0x4C,0x38,0x06,0x00,0x00, /* Q */
|
||||||
|
0x00,0x00,0x00,0xF8,0x44,0x44,0x44,0x78,0x50,0x48,0x48,0x44,0xE6,0x00,0x00,0x00, /* R */
|
||||||
|
0x00,0x00,0x00,0x3E,0x42,0x42,0x40,0x30,0x0C,0x02,0x42,0x42,0x7C,0x00,0x00,0x00, /* S */
|
||||||
|
0x00,0x00,0x00,0xFE,0x92,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00, /* T */
|
||||||
|
0x00,0x00,0x00,0xEE,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00,0x00, /* U */
|
||||||
|
0x00,0x00,0x00,0xEE,0x44,0x44,0x44,0x28,0x28,0x28,0x28,0x10,0x10,0x00,0x00,0x00, /* V */
|
||||||
|
0x00,0x00,0x00,0xD6,0x54,0x54,0x54,0x54,0x6C,0x28,0x28,0x28,0x28,0x00,0x00,0x00, /* W */
|
||||||
|
0x00,0x00,0x00,0xEE,0x44,0x28,0x28,0x10,0x10,0x28,0x28,0x44,0xEE,0x00,0x00,0x00, /* X */
|
||||||
|
0x00,0x00,0x00,0xEE,0x44,0x44,0x28,0x28,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00, /* Y */
|
||||||
|
0x00,0x00,0x00,0x3E,0x44,0x04,0x08,0x08,0x10,0x10,0x20,0x22,0x7E,0x00,0x00,0x00, /* Z */
|
||||||
|
0x00,0x00,0x3C,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3C,0x00, /* [ */
|
||||||
|
0x00,0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x08,0x04,0x04,0x04,0x02,0x00, /* \ */
|
||||||
|
0x00,0x00,0x3C,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x3C,0x00, /* ] */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ^ */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* _ */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ` */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x1C,0x24,0x44,0x44,0x3E,0x00,0x00,0x00,0x00, /* a */
|
||||||
|
0x00,0x00,0x00,0xC0,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42,0x7C,0x00,0x00,0x00, /* b */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x1C,0x22,0x40,0x40,0x40,0x22,0x1C,0x00,0x00,0x00,0x00, /* c */
|
||||||
|
0x00,0x00,0x00,0x0C,0x04,0x04,0x7C,0x84,0x84,0x84,0x84,0x8C,0x76,0x00,0x00,0x00, /* d */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x7E,0x40,0x40,0x42,0x3C,0x00,0x00,0x00,0x00, /* e */
|
||||||
|
0x00,0x00,0x00,0x0E,0x12,0x10,0x7C,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,0x00, /* f */
|
||||||
|
0x00,0x00,0x00,0x00,0x3E,0x44,0x44,0x38,0x40,0x3C,0x42,0x42,0x3C,0x00,0x00,0x00, /* g */
|
||||||
|
0x00,0x00,0x00,0xC0,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42,0xE7,0x00,0x00,0x00, /* h */
|
||||||
|
0x00,0x00,0x00,0x30,0x30,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,0x00, /* i */
|
||||||
|
0x00,0x00,0x0C,0x0C,0x00,0x1C,0x04,0x04,0x04,0x04,0x04,0x04,0x44,0x78,0x00,0x00, /* j */
|
||||||
|
0x00,0x00,0x00,0xC0,0x40,0x40,0x4E,0x48,0x50,0x68,0x48,0x44,0xEE,0x00,0x00,0x00, /* k */
|
||||||
|
0x00,0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,0x00, /* l */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0xF8,0x54,0x54,0x54,0x54,0x54,0xD6,0x00,0x00,0x00,0x00, /* m */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0xDC,0x62,0x42,0x42,0x42,0x42,0xE7,0x00,0x00,0x00,0x00, /* n */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x24,0x18,0x00,0x00,0x00,0x00, /* o */
|
||||||
|
0x00,0x00,0x00,0x00,0xDC,0x62,0x42,0x42,0x42,0x42,0x7C,0x40,0xE0,0x00,0x00,0x00, /* p */
|
||||||
|
0x00,0x00,0x00,0x00,0x7C,0x84,0x84,0x84,0x84,0x8C,0x74,0x04,0x0E,0x00,0x00,0x00, /* q */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0xEE,0x32,0x20,0x20,0x20,0x20,0xF8,0x00,0x00,0x00,0x00, /* r */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x3C,0x44,0x40,0x38,0x04,0x44,0x78,0x00,0x00,0x00,0x00, /* s */
|
||||||
|
0x00,0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x10,0x10,0x10,0x0C,0x00,0x00,0x00, /* t */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0xC6,0x42,0x42,0x42,0x42,0x46,0x3B,0x00,0x00,0x00,0x00, /* u */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x28,0x10,0x10,0x00,0x00,0x00,0x00, /* v */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0xD6,0x54,0x54,0x54,0x28,0x28,0x28,0x00,0x00,0x00,0x00, /* w */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x6E,0x24,0x18,0x18,0x18,0x24,0x76,0x00,0x00,0x00,0x00, /* x */
|
||||||
|
0x00,0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x28,0x18,0x10,0x10,0xE0,0x00,0x00,0x00, /* y */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x7E,0x44,0x08,0x10,0x10,0x22,0x7E,0x00,0x00,0x00,0x00, /* z */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void oled_command(uint8_t cmd) {
|
||||||
|
digitalWrite(PIN_OLED_DC, LOW);
|
||||||
|
digitalWrite(PIN_OLED_CS, LOW);
|
||||||
|
SPI.transfer(cmd);
|
||||||
|
digitalWrite(PIN_OLED_CS, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void oled_data(uint8_t dat) {
|
||||||
|
digitalWrite(PIN_OLED_DC, HIGH);
|
||||||
|
digitalWrite(PIN_OLED_CS, LOW);
|
||||||
|
SPI.transfer(dat);
|
||||||
|
digitalWrite(PIN_OLED_CS, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convertit 1 octet noir/blanc (8 pixels) en 4 octets de niveaux de gris
|
||||||
|
// (2 pixels par octet, format SSD1322 4 bits/pixel).
|
||||||
|
static void data_processing(uint8_t temp) {
|
||||||
|
uint8_t hi, lo;
|
||||||
|
hi = (temp & 0x80) ? 0xF0 : 0x00;
|
||||||
|
lo = (temp & 0x40) ? 0x0F : 0x00;
|
||||||
|
oled_data(hi | lo);
|
||||||
|
hi = (temp & 0x20) ? 0xF0 : 0x00;
|
||||||
|
lo = (temp & 0x10) ? 0x0F : 0x00;
|
||||||
|
oled_data(hi | lo);
|
||||||
|
hi = (temp & 0x08) ? 0xF0 : 0x00;
|
||||||
|
lo = (temp & 0x04) ? 0x0F : 0x00;
|
||||||
|
oled_data(hi | lo);
|
||||||
|
hi = (temp & 0x02) ? 0xF0 : 0x00;
|
||||||
|
lo = (temp & 0x01) ? 0x0F : 0x00;
|
||||||
|
oled_data(hi | lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void er_oled_SetWindow(uint8_t Xstart, uint8_t Ystart, uint8_t Xend, uint8_t Yend) {
|
||||||
|
oled_command(0x15);
|
||||||
|
oled_data(Xstart + 0x1C);
|
||||||
|
oled_data(Xend + 0x1C);
|
||||||
|
oled_command(0x75);
|
||||||
|
oled_data(Ystart);
|
||||||
|
oled_data(Yend);
|
||||||
|
oled_command(0x5C); // write RAM
|
||||||
|
}
|
||||||
|
|
||||||
|
void er_oled_clear() {
|
||||||
|
er_oled_SetWindow(0x00, 0x00, 0x77, 0x7F);
|
||||||
|
for (int row = 0; row < 128; row++) {
|
||||||
|
for (int i = 0; i < 240; i++) {
|
||||||
|
oled_data(0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void er_oled_char(uint8_t x, uint8_t y, const char *ascii, uint8_t mode) {
|
||||||
|
x = x / 4;
|
||||||
|
uint16_t offset = (*ascii - 32) * 16;
|
||||||
|
er_oled_SetWindow(x, y, x + 1, y + 15);
|
||||||
|
for (uint8_t i = 0; i < 16; i++) {
|
||||||
|
uint8_t b = pgm_read_byte(&AsciiLib[offset + i]);
|
||||||
|
if (mode) b = ~b;
|
||||||
|
data_processing(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void er_oled_string(uint8_t x, uint8_t y, const char *pString, uint8_t mode) {
|
||||||
|
while (*pString != 0) {
|
||||||
|
er_oled_char(x, y, pString, mode);
|
||||||
|
x += 8;
|
||||||
|
pString += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void er_oled_begin() {
|
||||||
|
pinMode(PIN_OLED_RST, OUTPUT);
|
||||||
|
pinMode(PIN_OLED_DC, OUTPUT);
|
||||||
|
pinMode(PIN_OLED_CS, OUTPUT);
|
||||||
|
|
||||||
|
// Broches SPI personnalisees : sck, miso (non cable), mosi, ss
|
||||||
|
SPI.begin(PIN_OLED_CLK, -1, PIN_OLED_MOSI, PIN_OLED_CS);
|
||||||
|
SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0));
|
||||||
|
|
||||||
|
digitalWrite(PIN_OLED_CS, LOW);
|
||||||
|
digitalWrite(PIN_OLED_RST, HIGH);
|
||||||
|
delay(10);
|
||||||
|
digitalWrite(PIN_OLED_RST, LOW);
|
||||||
|
delay(10);
|
||||||
|
digitalWrite(PIN_OLED_RST, HIGH);
|
||||||
|
|
||||||
|
oled_command(0xFD); // set command lock
|
||||||
|
oled_data(0x12); // unlock
|
||||||
|
oled_command(0xAE); // display off
|
||||||
|
oled_command(0xB3); // clock divider / osc frequency
|
||||||
|
oled_data(0x91);
|
||||||
|
oled_command(0xCA); // multiplex ratio
|
||||||
|
oled_data(0x3F); // duty = 1/64
|
||||||
|
oled_command(0xA2); // display offset
|
||||||
|
oled_data(0x00);
|
||||||
|
oled_command(0xA1); // start line
|
||||||
|
oled_data(0x00);
|
||||||
|
oled_command(0xA0); // set remap
|
||||||
|
oled_data(0x14);
|
||||||
|
oled_data(0x11);
|
||||||
|
oled_command(0xAB); // function selection
|
||||||
|
oled_data(0x01); // external VDD
|
||||||
|
oled_command(0xB4);
|
||||||
|
oled_data(0xA0);
|
||||||
|
oled_data(0xFD);
|
||||||
|
oled_command(0xC1); // contrast current
|
||||||
|
oled_data(0x80);
|
||||||
|
oled_command(0xC7); // master contrast current control
|
||||||
|
oled_data(0x0F);
|
||||||
|
oled_command(0xB1); // phase length
|
||||||
|
oled_data(0xE2);
|
||||||
|
oled_command(0xD1);
|
||||||
|
oled_data(0x82);
|
||||||
|
oled_data(0x20);
|
||||||
|
oled_command(0xBB); // pre-charge voltage
|
||||||
|
oled_data(0x1F);
|
||||||
|
oled_command(0xB6); // second pre-charge period
|
||||||
|
oled_data(0x08);
|
||||||
|
oled_command(0xBE); // VCOMH
|
||||||
|
oled_data(0x07);
|
||||||
|
oled_command(0xA6); // normal display
|
||||||
|
oled_command(0xAF); // display on
|
||||||
|
}
|
||||||
18
src/er_oled.h
Normal file
18
src/er_oled.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Driver bas niveau pour ecran ER-OLEDM032-1 (controleur SSD1322, 256x64,
|
||||||
|
// SPI 4 fils). Adapte du tutoriel constructeur (buydisplay.com) pour
|
||||||
|
// utiliser les broches SPI personnalisees de l'ESP32-C3 (voir config.h) et
|
||||||
|
// depouille des fonctions d'affichage bitmap, inutiles pour ce projet
|
||||||
|
// (dashboard texte uniquement).
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#define OLED_X_MAXPIXEL 256
|
||||||
|
#define OLED_Y_MAXPIXEL 64
|
||||||
|
|
||||||
|
void er_oled_begin();
|
||||||
|
void er_oled_clear();
|
||||||
|
void er_oled_SetWindow(uint8_t Xstart, uint8_t Ystart, uint8_t Xend, uint8_t Yend);
|
||||||
|
void er_oled_char(uint8_t x, uint8_t y, const char *ascii, uint8_t mode);
|
||||||
|
void er_oled_string(uint8_t x, uint8_t y, const char *pString, uint8_t mode);
|
||||||
34
src/main.cpp
34
src/main.cpp
@ -1,8 +1,42 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "oled_ui.h"
|
||||||
|
#include "tms_link.h"
|
||||||
|
#include "web_ui.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Clignotement 1 Hz de la LED RGB embarquee, vert a 30% de luminosite,
|
||||||
|
// pour indiquer que le firmware tourne.
|
||||||
|
const uint32_t STATUS_LED_PERIOD_MS = 500;
|
||||||
|
const uint8_t STATUS_LED_GREEN = (uint8_t)(255 * 0.30f);
|
||||||
|
uint32_t g_lastStatusLedMs = 0;
|
||||||
|
bool g_statusLedOn = false;
|
||||||
|
|
||||||
|
void updateStatusLed() {
|
||||||
|
uint32_t now = millis();
|
||||||
|
if (now - g_lastStatusLedMs < STATUS_LED_PERIOD_MS) return;
|
||||||
|
g_lastStatusLedMs = now;
|
||||||
|
g_statusLedOn = !g_statusLedOn;
|
||||||
|
neopixelWrite(PIN_RGB_LED, 0, g_statusLedOn ? STATUS_LED_GREEN : 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
Serial.println("ESP32-C3-dualboost");
|
||||||
|
Serial.println(TMS_DUMMY_MODE ? "Mode simulation TMS320 (dummy)" : "Mode liaison TMS320 reelle");
|
||||||
|
|
||||||
|
TmsLink::begin();
|
||||||
|
OledUi::begin();
|
||||||
|
WebUi::begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
TmsLink::poll();
|
||||||
|
OledUi::update(TmsLink::telemetry(), TmsLink::linkOk());
|
||||||
|
WebUi::poll();
|
||||||
|
updateStatusLed();
|
||||||
}
|
}
|
||||||
|
|||||||
84
src/oled_ui.cpp
Normal file
84
src/oled_ui.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#include "oled_ui.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "er_oled.h"
|
||||||
|
#include "tms_link.h"
|
||||||
|
|
||||||
|
namespace OledUi {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const uint32_t REFRESH_PERIOD_MS = 500;
|
||||||
|
const uint32_t PAGE_PERIOD_MS = 3000;
|
||||||
|
|
||||||
|
uint32_t g_lastRefreshMs = 0;
|
||||||
|
uint32_t g_lastPageChangeMs = 0;
|
||||||
|
uint8_t g_page = 0;
|
||||||
|
const uint8_t PAGE_COUNT = 3;
|
||||||
|
|
||||||
|
void drawLine(uint8_t y, const char *text) {
|
||||||
|
char padded[33];
|
||||||
|
snprintf(padded, sizeof(padded), "%-32s", text);
|
||||||
|
er_oled_string(0, y, padded, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawEntreeCommandes(const Telemetry &t, bool linkOk) {
|
||||||
|
char l0[33], l1[33], l2[33], l3[33];
|
||||||
|
snprintf(l0, sizeof(l0), "TMS320: %s", linkOk ? "OK" : "PERDU");
|
||||||
|
snprintf(l1, sizeof(l1), "Vin=%.1fV Iin=%.2fA", t.vin, t.iin);
|
||||||
|
snprintf(l2, sizeof(l2), "Iout=%.2fA", t.iout);
|
||||||
|
snprintf(l3, sizeof(l3), "HT:%s PWM1:%s PWM2:%s", TmsLink::command().ht ? "ON " : "OFF",
|
||||||
|
TmsLink::command().pwm1 ? "ON " : "OFF", TmsLink::command().pwm2 ? "ON " : "OFF");
|
||||||
|
drawLine(0, l0);
|
||||||
|
drawLine(16, l1);
|
||||||
|
drawLine(32, l2);
|
||||||
|
drawLine(48, l3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawEtage1(const Telemetry &t) {
|
||||||
|
char l1[33], l2[33];
|
||||||
|
snprintf(l1, sizeof(l1), "F=%.0fHz D=%.1f%%", t.freq1, t.duty1);
|
||||||
|
snprintf(l2, sizeof(l2), "V=%.1fV I=%.2fA T=%.1fC", t.v1, t.i1, t.t1);
|
||||||
|
drawLine(0, "ETAGE 1");
|
||||||
|
drawLine(16, l1);
|
||||||
|
drawLine(32, l2);
|
||||||
|
drawLine(48, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawEtage2(const Telemetry &t) {
|
||||||
|
char l1[33], l2[33];
|
||||||
|
snprintf(l1, sizeof(l1), "F=%.0fHz D=%.1f%%", t.freq2, t.duty2);
|
||||||
|
snprintf(l2, sizeof(l2), "V=%.1fV I=%.2fA T=%.1fC", t.vout, t.i2, t.t2);
|
||||||
|
drawLine(0, "ETAGE 2");
|
||||||
|
drawLine(16, l1);
|
||||||
|
drawLine(32, l2);
|
||||||
|
drawLine(48, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void begin() {
|
||||||
|
er_oled_begin();
|
||||||
|
er_oled_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(const Telemetry &t, bool linkOk) {
|
||||||
|
uint32_t now = millis();
|
||||||
|
|
||||||
|
if (now - g_lastPageChangeMs >= PAGE_PERIOD_MS) {
|
||||||
|
g_lastPageChangeMs = now;
|
||||||
|
g_page = (g_page + 1) % PAGE_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (now - g_lastRefreshMs < REFRESH_PERIOD_MS) return;
|
||||||
|
g_lastRefreshMs = now;
|
||||||
|
|
||||||
|
switch (g_page) {
|
||||||
|
case 0: drawEntreeCommandes(t, linkOk); break;
|
||||||
|
case 1: drawEtage1(t); break;
|
||||||
|
case 2: drawEtage2(t); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace OledUi
|
||||||
13
src/oled_ui.h
Normal file
13
src/oled_ui.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "protocol.h"
|
||||||
|
|
||||||
|
namespace OledUi {
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
// A appeler en boucle. Redessine l'ecran periodiquement et fait tourner
|
||||||
|
// les pages (entree/commandes, etage 1, etage 2).
|
||||||
|
void update(const Telemetry &t, bool linkOk);
|
||||||
|
|
||||||
|
} // namespace OledUi
|
||||||
172
src/tms_link.cpp
Normal file
172
src/tms_link.cpp
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
#include "tms_link.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
namespace TmsLink {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Telemetry g_telemetry;
|
||||||
|
CommandState g_command;
|
||||||
|
uint32_t g_lastValidFrameMs = 0;
|
||||||
|
uint32_t g_lastCommandSentMs = 0;
|
||||||
|
|
||||||
|
char g_lineBuf[160];
|
||||||
|
uint8_t g_lineLen = 0;
|
||||||
|
|
||||||
|
const uint32_t COMMAND_SEND_PERIOD_MS = 500;
|
||||||
|
const uint32_t SIM_UPDATE_PERIOD_MS = 200;
|
||||||
|
uint32_t g_lastSimMs = 0;
|
||||||
|
|
||||||
|
uint8_t checksumOf(const char *s, size_t len) {
|
||||||
|
uint8_t cs = 0;
|
||||||
|
for (size_t i = 0; i < len; i++) cs ^= (uint8_t)s[i];
|
||||||
|
return cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Applique une valeur "TAG=xxx" a la telemetrie courante.
|
||||||
|
void applyField(const char *tag, float value) {
|
||||||
|
if (!strcmp(tag, "FREQ1")) g_telemetry.freq1 = value;
|
||||||
|
else if (!strcmp(tag, "FREQ2")) g_telemetry.freq2 = value;
|
||||||
|
else if (!strcmp(tag, "DUTY1")) g_telemetry.duty1 = value;
|
||||||
|
else if (!strcmp(tag, "DUTY2")) g_telemetry.duty2 = value;
|
||||||
|
else if (!strcmp(tag, "VIN")) g_telemetry.vin = value;
|
||||||
|
else if (!strcmp(tag, "IIN")) g_telemetry.iin = value;
|
||||||
|
else if (!strcmp(tag, "V1")) g_telemetry.v1 = value;
|
||||||
|
else if (!strcmp(tag, "I1")) g_telemetry.i1 = value;
|
||||||
|
else if (!strcmp(tag, "T1")) g_telemetry.t1 = value;
|
||||||
|
else if (!strcmp(tag, "VOUT")) g_telemetry.vout = value;
|
||||||
|
else if (!strcmp(tag, "I2")) g_telemetry.i2 = value;
|
||||||
|
else if (!strcmp(tag, "T2")) g_telemetry.t2 = value;
|
||||||
|
else if (!strcmp(tag, "IOUT")) g_telemetry.iout = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse une ligne "$T,TAG=val,TAG=val,...*XX". Retourne true si le
|
||||||
|
// checksum est valide et que la trame a bien ete appliquee.
|
||||||
|
bool parseTelemetryLine(char *line) {
|
||||||
|
size_t len = strlen(line);
|
||||||
|
if (len < 5 || line[0] != '$' || line[1] != 'T' || line[2] != ',') return false;
|
||||||
|
|
||||||
|
char *star = strrchr(line, '*');
|
||||||
|
if (!star || star - line < 3) return false;
|
||||||
|
|
||||||
|
uint8_t rxChecksum = (uint8_t)strtol(star + 1, nullptr, 16);
|
||||||
|
uint8_t computed = checksumOf(line + 1, star - (line + 1));
|
||||||
|
if (rxChecksum != computed) return false;
|
||||||
|
|
||||||
|
*star = '\0';
|
||||||
|
char *field = line + 3; // apres "$T,"
|
||||||
|
char *saveptr = nullptr;
|
||||||
|
char *tok = strtok_r(field, ",", &saveptr);
|
||||||
|
while (tok) {
|
||||||
|
char *eq = strchr(tok, '=');
|
||||||
|
if (eq) {
|
||||||
|
*eq = '\0';
|
||||||
|
applyField(tok, atof(eq + 1));
|
||||||
|
}
|
||||||
|
tok = strtok_r(nullptr, ",", &saveptr);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pollUart() {
|
||||||
|
while (Serial1.available()) {
|
||||||
|
char c = (char)Serial1.read();
|
||||||
|
if (c == '\n') {
|
||||||
|
g_lineBuf[g_lineLen] = '\0';
|
||||||
|
if (parseTelemetryLine(g_lineBuf)) {
|
||||||
|
g_telemetry.lastUpdateMs = millis();
|
||||||
|
g_lastValidFrameMs = g_telemetry.lastUpdateMs;
|
||||||
|
}
|
||||||
|
g_lineLen = 0;
|
||||||
|
} else if (c != '\r') {
|
||||||
|
if (g_lineLen < sizeof(g_lineBuf) - 1) {
|
||||||
|
g_lineBuf[g_lineLen++] = c;
|
||||||
|
} else {
|
||||||
|
g_lineLen = 0; // ligne trop longue, on repart de zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simule un convertisseur en fonctionnement pour pouvoir developper et
|
||||||
|
// tester l'IHM (OLED + web) sans firmware TMS320.
|
||||||
|
void updateSimulation() {
|
||||||
|
uint32_t now = millis();
|
||||||
|
if (now - g_lastSimMs < SIM_UPDATE_PERIOD_MS) return;
|
||||||
|
g_lastSimMs = now;
|
||||||
|
|
||||||
|
float t = now / 1000.0f;
|
||||||
|
bool running = g_command.ht;
|
||||||
|
|
||||||
|
g_telemetry.freq1 = 100000.0f;
|
||||||
|
g_telemetry.freq2 = 100000.0f;
|
||||||
|
g_telemetry.duty1 = running && g_command.pwm1 ? 45.0f + 2.0f * sinf(t) : 0.0f;
|
||||||
|
g_telemetry.duty2 = running && g_command.pwm2 ? 50.0f + 2.0f * sinf(t + 1.0f) : 0.0f;
|
||||||
|
|
||||||
|
g_telemetry.vin = 400.0f + 1.0f * sinf(t * 0.5f);
|
||||||
|
g_telemetry.iin = running ? 1.2f + 0.1f * sinf(t) : 0.05f;
|
||||||
|
|
||||||
|
g_telemetry.v1 = running && g_command.pwm1 ? 200.0f + 0.5f * sinf(t) : 0.0f;
|
||||||
|
g_telemetry.i1 = running && g_command.pwm1 ? 2.5f + 0.2f * sinf(t * 1.3f) : 0.0f;
|
||||||
|
g_telemetry.t1 = 40.0f + 5.0f * sinf(t * 0.1f);
|
||||||
|
|
||||||
|
g_telemetry.vout = running && g_command.pwm2 ? 200.0f + 0.5f * sinf(t + 0.3f) : 0.0f;
|
||||||
|
g_telemetry.i2 = running && g_command.pwm2 ? 2.48f + 0.2f * sinf(t * 1.1f) : 0.0f;
|
||||||
|
g_telemetry.t2 = 39.5f + 5.0f * sinf(t * 0.1f + 0.5f);
|
||||||
|
|
||||||
|
g_telemetry.iout = running ? 1.05f + 0.1f * sinf(t * 0.8f) : 0.0f;
|
||||||
|
|
||||||
|
g_telemetry.lastUpdateMs = now;
|
||||||
|
g_lastValidFrameMs = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendCommandFrame() {
|
||||||
|
char body[48];
|
||||||
|
int n = snprintf(body, sizeof(body), "C,HT=%d,PWM1=%d,PWM2=%d", g_command.ht ? 1 : 0,
|
||||||
|
g_command.pwm1 ? 1 : 0, g_command.pwm2 ? 1 : 0);
|
||||||
|
uint8_t cs = checksumOf(body, n);
|
||||||
|
|
||||||
|
char frame[64];
|
||||||
|
snprintf(frame, sizeof(frame), "$%s*%02X\n", body, cs);
|
||||||
|
Serial1.print(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void begin() {
|
||||||
|
Serial1.begin(TMS_UART_BAUD, SERIAL_8N1, PIN_TMS_UART_RX, PIN_TMS_UART_TX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void poll() {
|
||||||
|
if (TMS_DUMMY_MODE) {
|
||||||
|
updateSimulation();
|
||||||
|
} else {
|
||||||
|
pollUart();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t now = millis();
|
||||||
|
if (now - g_lastCommandSentMs >= COMMAND_SEND_PERIOD_MS) {
|
||||||
|
g_lastCommandSentMs = now;
|
||||||
|
sendCommandFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCommand(const CommandState &cmd) {
|
||||||
|
g_command = cmd;
|
||||||
|
sendCommandFrame();
|
||||||
|
g_lastCommandSentMs = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Telemetry &telemetry() { return g_telemetry; }
|
||||||
|
const CommandState &command() { return g_command; }
|
||||||
|
|
||||||
|
bool linkOk() {
|
||||||
|
if (TMS_DUMMY_MODE) return true;
|
||||||
|
return (millis() - g_lastValidFrameMs) < 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace TmsLink
|
||||||
23
src/tms_link.h
Normal file
23
src/tms_link.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "protocol.h"
|
||||||
|
|
||||||
|
namespace TmsLink {
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
// A appeler en boucle : lit/parse l'UART (ou simule si TMS_DUMMY_MODE) et
|
||||||
|
// envoie periodiquement la trame de commande courante.
|
||||||
|
void poll();
|
||||||
|
|
||||||
|
// Met a jour l'etat de commande a transmettre au TMS320 au prochain envoi.
|
||||||
|
void setCommand(const CommandState &cmd);
|
||||||
|
|
||||||
|
const Telemetry &telemetry();
|
||||||
|
const CommandState &command();
|
||||||
|
|
||||||
|
// true si une trame de telemetrie valide (checksum OK) a ete recue
|
||||||
|
// recemment (ou si on est en mode simulation).
|
||||||
|
bool linkOk();
|
||||||
|
|
||||||
|
} // namespace TmsLink
|
||||||
11
src/web_ui.cpp
Normal file
11
src/web_ui.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include "web_ui.h"
|
||||||
|
|
||||||
|
// TODO : serveur web IHM, connexion WiFi en mode STA au reseau local
|
||||||
|
// (SSID/mot de passe a definir), une fois l'affichage OLED valide.
|
||||||
|
|
||||||
|
namespace WebUi {
|
||||||
|
|
||||||
|
void begin() {}
|
||||||
|
void poll() {}
|
||||||
|
|
||||||
|
} // namespace WebUi
|
||||||
12
src/web_ui.h
Normal file
12
src/web_ui.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Stub pour l'instant : la priorite est de valider l'affichage OLED avec
|
||||||
|
// la simulation TMS320 avant de brancher le serveur web (qui devra se
|
||||||
|
// connecter au reseau local, en mode STA, avec des identifiants a fournir).
|
||||||
|
|
||||||
|
namespace WebUi {
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
void poll();
|
||||||
|
|
||||||
|
} // namespace WebUi
|
||||||
Reference in New Issue
Block a user