mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-27 01:56:14 +01:00
Transmit DCC packet to loco
This commit is contained in:
parent
10209ed6f3
commit
005ddef665
83
DCCRMT.cpp
83
DCCRMT.cpp
|
@ -55,7 +55,7 @@ void setEOT(rmt_item32_t* item) {
|
||||||
|
|
||||||
void IRAM_ATTR interrupt(rmt_channel_t channel, void *t) {
|
void IRAM_ATTR interrupt(rmt_channel_t channel, void *t) {
|
||||||
RMTPin *tt = (RMTPin *)t;
|
RMTPin *tt = (RMTPin *)t;
|
||||||
tt->RMTinterrupt(channel);
|
tt->RMTinterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
RMTPin::RMTPin(byte pin, byte ch, byte plen) {
|
RMTPin::RMTPin(byte pin, byte ch, byte plen) {
|
||||||
|
@ -65,7 +65,7 @@ RMTPin::RMTPin(byte pin, byte ch, byte plen) {
|
||||||
preamble = (rmt_item32_t*)malloc(preambleLen*sizeof(rmt_item32_t));
|
preamble = (rmt_item32_t*)malloc(preambleLen*sizeof(rmt_item32_t));
|
||||||
for (byte n=0; n<plen; n++)
|
for (byte n=0; n<plen; n++)
|
||||||
setDCCBit1(preamble + n); // preamble bits
|
setDCCBit1(preamble + n); // preamble bits
|
||||||
setDCCBit0Last(preamble + plen); // start of packet 0 bit
|
setDCCBit0(preamble + plen); // start of packet 0 bit
|
||||||
setEOT(preamble + plen + 1); // EOT marker
|
setEOT(preamble + plen + 1); // EOT marker
|
||||||
|
|
||||||
// idle
|
// idle
|
||||||
|
@ -81,6 +81,10 @@ RMTPin::RMTPin(byte pin, byte ch, byte plen) {
|
||||||
setDCCBit0Last(idle + 27); // finish always with 0
|
setDCCBit0Last(idle + 27); // finish always with 0
|
||||||
setEOT(idle + 28); // EOT marker
|
setEOT(idle + 28); // EOT marker
|
||||||
|
|
||||||
|
// data: max packet size today is 5 + checksum
|
||||||
|
dataLen = (5+1)*9+2; // Each byte has one bit extra and one 0 bit and one EOF marker
|
||||||
|
data = (rmt_item32_t*)malloc(dataLen*sizeof(rmt_item32_t));
|
||||||
|
|
||||||
rmt_config_t config;
|
rmt_config_t config;
|
||||||
// Configure the RMT channel for TX
|
// Configure the RMT channel for TX
|
||||||
bzero(&config, sizeof(rmt_config_t));
|
bzero(&config, sizeof(rmt_config_t));
|
||||||
|
@ -88,9 +92,10 @@ RMTPin::RMTPin(byte pin, byte ch, byte plen) {
|
||||||
config.channel = channel = (rmt_channel_t)ch;
|
config.channel = channel = (rmt_channel_t)ch;
|
||||||
config.clk_div = 1; // use 80Mhz clock directly
|
config.clk_div = 1; // use 80Mhz clock directly
|
||||||
config.gpio_num = (gpio_num_t)pin;
|
config.gpio_num = (gpio_num_t)pin;
|
||||||
config.mem_block_num = 1; // With MAX_PACKET_SIZE = 5 and number of bits needed
|
config.mem_block_num = 2; // With longest DCC packet 11 inc checksum (future expansion)
|
||||||
// MAX_PACKET_SIZE+1 * 8 + MAX_PACKET_SIZE = 54 one
|
// number of bits needed is 22preamble + start +
|
||||||
// mem block of 64 RMT items (=DCC bits) should be enough
|
// 11*9 + extrazero + EOT = 124
|
||||||
|
// 2 mem block of 64 RMT items should be enough
|
||||||
|
|
||||||
// this was not our problem https://esp32.com/viewtopic.php?t=5252
|
// this was not our problem https://esp32.com/viewtopic.php?t=5252
|
||||||
//periph_module_disable(PERIPH_RMT_MODULE);
|
//periph_module_disable(PERIPH_RMT_MODULE);
|
||||||
|
@ -114,24 +119,54 @@ RMTPin::RMTPin(byte pin, byte ch, byte plen) {
|
||||||
|
|
||||||
// send one bit to kickstart the signal, remaining data will come from the
|
// send one bit to kickstart the signal, remaining data will come from the
|
||||||
// packet queue. We intentionally do not wait for the RMT TX complete here.
|
// packet queue. We intentionally do not wait for the RMT TX complete here.
|
||||||
rmt_write_items(channel, preamble, preambleLen, false);
|
//rmt_write_items(channel, preamble, preambleLen, false);
|
||||||
preambleNext = false;
|
RMTprefill();
|
||||||
dataNext = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR RMTPin::RMTinterrupt(rmt_channel_t channel) {
|
|
||||||
|
|
||||||
if (preambleNext) {
|
|
||||||
rmt_fill_tx_items(channel, preamble, preambleLen, 0);
|
|
||||||
preambleNext = false;
|
|
||||||
} else {
|
|
||||||
if (dataNext) {
|
|
||||||
rmt_fill_tx_items(channel, packetBits, packetLen, 0);
|
|
||||||
} else {
|
|
||||||
// here we should not get as now we need to send idle packet
|
|
||||||
rmt_fill_tx_items(channel, idle, idleLen, 0);
|
|
||||||
}
|
|
||||||
preambleNext = true;
|
preambleNext = true;
|
||||||
}
|
dataReady = false;
|
||||||
rmt_tx_start(channel,true);
|
RMTinterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RMTPin::RMTprefill() {
|
||||||
|
rmt_fill_tx_items(channel, preamble, preambleLen, 0);
|
||||||
|
rmt_fill_tx_items(channel, idle, idleLen, preambleLen-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const byte transmitMask[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
||||||
|
|
||||||
|
bool RMTPin::fillData(const byte buffer[], byte byteCount, byte repeatCount=1) {
|
||||||
|
if (dataReady == true || dataRepeat > 0) // we have still old work to do
|
||||||
|
return false;
|
||||||
|
byte bitcounter = 0;
|
||||||
|
for(byte n=0; n<byteCount; n++) {
|
||||||
|
for(byte bit=0; bit<8; bit++) {
|
||||||
|
if (buffer[n] & transmitMask[bit])
|
||||||
|
setDCCBit1(data + bitcounter++);
|
||||||
|
else
|
||||||
|
setDCCBit0(data + bitcounter++);
|
||||||
|
}
|
||||||
|
setDCCBit0(data + bitcounter++); // zero at end of each byte
|
||||||
|
}
|
||||||
|
setDCCBit1(data + bitcounter-1); // overwrite previous zero bit with one bit
|
||||||
|
setDCCBit0Last(data + bitcounter++); // extra 0 bit after end bit
|
||||||
|
setEOT(data + bitcounter++); // EOT marker
|
||||||
|
dataLen = bitcounter;
|
||||||
|
dataReady = true;
|
||||||
|
dataRepeat = repeatCount;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR RMTPin::RMTinterrupt() {
|
||||||
|
rmt_tx_start(channel,true);
|
||||||
|
/* byte foo[3];
|
||||||
|
foo[0] = 0xF0;
|
||||||
|
foo[1] = 0x0F;
|
||||||
|
foo[2] = 0xAA;
|
||||||
|
fillData(foo, 3);*/
|
||||||
|
if (dataReady) {
|
||||||
|
rmt_fill_tx_items(channel, data, dataLen, preambleLen-1);
|
||||||
|
dataReady = false;
|
||||||
|
}
|
||||||
|
if (dataRepeat > 0)
|
||||||
|
dataRepeat--;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
11
DCCRMT.h
11
DCCRMT.h
|
@ -29,7 +29,9 @@
|
||||||
class RMTPin {
|
class RMTPin {
|
||||||
public:
|
public:
|
||||||
RMTPin(byte pin, byte ch, byte plen);
|
RMTPin(byte pin, byte ch, byte plen);
|
||||||
void IRAM_ATTR RMTinterrupt(rmt_channel_t);
|
void IRAM_ATTR RMTinterrupt();
|
||||||
|
void RMTprefill();
|
||||||
|
bool fillData(const byte buffer[], byte byteCount, byte repeatCount);
|
||||||
|
|
||||||
static RMTPin mainRMTPin;
|
static RMTPin mainRMTPin;
|
||||||
static RMTPin progRMTPin;
|
static RMTPin progRMTPin;
|
||||||
|
@ -43,9 +45,10 @@ class RMTPin {
|
||||||
byte idleLen;
|
byte idleLen;
|
||||||
rmt_item32_t *preamble;
|
rmt_item32_t *preamble;
|
||||||
byte preambleLen;
|
byte preambleLen;
|
||||||
rmt_item32_t packetBits[64];
|
rmt_item32_t *data;
|
||||||
byte packetLen;
|
byte dataLen;
|
||||||
// flags
|
// flags
|
||||||
volatile bool preambleNext = true; // alternate between preamble and content
|
volatile bool preambleNext = true; // alternate between preamble and content
|
||||||
volatile bool dataNext = false; // do we have real data available or send idle
|
volatile bool dataReady = false; // do we have real data available or send idle
|
||||||
|
volatile byte dataRepeat = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include "DCCTimer.h"
|
#include "DCCTimer.h"
|
||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
#include "freeMemory.h"
|
#include "freeMemory.h"
|
||||||
#include "DCCRMT.h"
|
|
||||||
|
|
||||||
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
|
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
|
||||||
DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
||||||
|
@ -39,7 +38,7 @@ uint8_t DCCWaveform::trailingEdgeCounter=0;
|
||||||
|
|
||||||
void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) {
|
void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) {
|
||||||
|
|
||||||
RMTPin *p = new RMTPin(21, 0, PREAMBLE_BITS_MAIN);
|
mainTrack.rmtPin = new RMTPin(21, 0, PREAMBLE_BITS_MAIN);
|
||||||
|
|
||||||
mainTrack.motorDriver=mainDriver;
|
mainTrack.motorDriver=mainDriver;
|
||||||
progTrack.motorDriver=progDriver;
|
progTrack.motorDriver=progDriver;
|
||||||
|
@ -64,6 +63,13 @@ volatile bool ackflag = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void IRAM_ATTR DCCWaveform::loop(bool ackManagerActive) {
|
void IRAM_ATTR DCCWaveform::loop(bool ackManagerActive) {
|
||||||
|
|
||||||
|
if (mainTrack.packetPendingRMT) {
|
||||||
|
mainTrack.rmtPin->fillData(mainTrack.pendingPacket, mainTrack.pendingLength, mainTrack.pendingRepeats);
|
||||||
|
mainTrack.packetPendingRMT=false;
|
||||||
|
// sentResetsSincePacket = 0 // later when progtrack
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SLOW_ANALOG_READ
|
#ifdef SLOW_ANALOG_READ
|
||||||
if (ackflag) {
|
if (ackflag) {
|
||||||
progTrack.checkAck();
|
progTrack.checkAck();
|
||||||
|
@ -122,6 +128,7 @@ const byte bitMask[] = {0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
||||||
DCCWaveform::DCCWaveform( byte preambleBits, bool isMain) {
|
DCCWaveform::DCCWaveform( byte preambleBits, bool isMain) {
|
||||||
isMainTrack = isMain;
|
isMainTrack = isMain;
|
||||||
packetPending = false;
|
packetPending = false;
|
||||||
|
packetPendingRMT = false;
|
||||||
memcpy(transmitPacket, idlePacket, sizeof(idlePacket));
|
memcpy(transmitPacket, idlePacket, sizeof(idlePacket));
|
||||||
state = WAVE_START;
|
state = WAVE_START;
|
||||||
// The +1 below is to allow the preamble generator to create the stop bit
|
// The +1 below is to allow the preamble generator to create the stop bit
|
||||||
|
@ -290,7 +297,7 @@ void IRAM_ATTR DCCWaveform::interrupt2() {
|
||||||
// Wait until there is no packet pending, then make this pending
|
// Wait until there is no packet pending, then make this pending
|
||||||
void DCCWaveform::schedulePacket(const byte buffer[], byte byteCount, byte repeats) {
|
void DCCWaveform::schedulePacket(const byte buffer[], byte byteCount, byte repeats) {
|
||||||
if (byteCount > MAX_PACKET_SIZE) return; // allow for chksum
|
if (byteCount > MAX_PACKET_SIZE) return; // allow for chksum
|
||||||
while (packetPending);
|
while (packetPending||packetPendingRMT);
|
||||||
portENTER_CRITICAL(&timerMux);
|
portENTER_CRITICAL(&timerMux);
|
||||||
byte checksum = 0;
|
byte checksum = 0;
|
||||||
for (byte b = 0; b < byteCount; b++) {
|
for (byte b = 0; b < byteCount; b++) {
|
||||||
|
@ -302,6 +309,7 @@ void DCCWaveform::schedulePacket(const byte buffer[], byte byteCount, byte repea
|
||||||
pendingLength = byteCount + 1;
|
pendingLength = byteCount + 1;
|
||||||
pendingRepeats = repeats;
|
pendingRepeats = repeats;
|
||||||
packetPending = true;
|
packetPending = true;
|
||||||
|
packetPendingRMT = true;
|
||||||
sentResetsSincePacket=0;
|
sentResetsSincePacket=0;
|
||||||
portEXIT_CRITICAL(&timerMux);
|
portEXIT_CRITICAL(&timerMux);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#ifndef DCCWaveform_h
|
#ifndef DCCWaveform_h
|
||||||
#define DCCWaveform_h
|
#define DCCWaveform_h
|
||||||
|
|
||||||
|
#include "DCCRMT.h"
|
||||||
#include "MotorDriver.h"
|
#include "MotorDriver.h"
|
||||||
|
|
||||||
// Wait times for power management. Unit: milliseconds
|
// Wait times for power management. Unit: milliseconds
|
||||||
|
@ -82,6 +83,7 @@ class DCCWaveform {
|
||||||
}
|
}
|
||||||
void schedulePacket(const byte buffer[], byte byteCount, byte repeats);
|
void schedulePacket(const byte buffer[], byte byteCount, byte repeats);
|
||||||
volatile bool packetPending;
|
volatile bool packetPending;
|
||||||
|
volatile bool packetPendingRMT;
|
||||||
volatile byte sentResetsSincePacket;
|
volatile byte sentResetsSincePacket;
|
||||||
volatile bool autoPowerOff=false;
|
volatile bool autoPowerOff=false;
|
||||||
void setAckBaseline(); //prog track only
|
void setAckBaseline(); //prog track only
|
||||||
|
@ -122,6 +124,7 @@ class DCCWaveform {
|
||||||
|
|
||||||
bool isMainTrack;
|
bool isMainTrack;
|
||||||
MotorDriver* motorDriver;
|
MotorDriver* motorDriver;
|
||||||
|
RMTPin* rmtPin;
|
||||||
// Transmission controller
|
// Transmission controller
|
||||||
byte transmitPacket[MAX_PACKET_SIZE+1]; // +1 for checksum
|
byte transmitPacket[MAX_PACKET_SIZE+1]; // +1 for checksum
|
||||||
byte transmitLength;
|
byte transmitLength;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
#define GITHUB_SHA "ESP32-2021114-15:35"
|
#define GITHUB_SHA "ESP32-2021115-22:27"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user