From 47fc42d09a944cecdc175d452c869c077fe3dc7f Mon Sep 17 00:00:00 2001 From: Martin-Laclaustra Date: Mon, 30 Mar 2020 11:22:21 +0200 Subject: [PATCH] interrupt() call to child replaced by pointer to a static function with instance as argument --- src/I2S/I2S.cpp | 17 +++++++- src/I2S/I2S.h | 3 +- src/VGA/VGA14BitI.h | 79 +++++++++++++++++++++++++-------- src/VGA/VGA3BitI.h | 99 +++++++++++++++++++++++------------------- src/VGA/VGA6BitI.h | 103 +++++++++++++++++++++++--------------------- 5 files changed, 188 insertions(+), 113 deletions(-) diff --git a/src/I2S/I2S.cpp b/src/I2S/I2S.cpp index fedca12..7cb6a65 100644 --- a/src/I2S/I2S.cpp +++ b/src/I2S/I2S.cpp @@ -32,8 +32,21 @@ I2S::I2S(const int i2sIndex) void IRAM_ATTR I2S::interruptStatic(void *arg) { volatile i2s_dev_t &i2s = *i2sDevices[((I2S *)arg)->i2sIndex]; - i2s.int_clr.val = i2s.int_raw.val; - ((I2S *)arg)->interrupt(); + //i2s object not safely accesed in DRAM or IRAM + //i2s.int_clr.val = i2s.int_raw.val; + //using REG_WRITE to clear the interrupt instead + //note: there are still other alternatives, see i2s driver .c file + //inside the i2s_intr_handler_default() function + REG_WRITE(I2S_INT_CLR_REG(((I2S *)arg)->i2sIndex), (REG_READ(I2S_INT_RAW_REG(((I2S *)arg)->i2sIndex)) & 0xffffffc0) | 0x3f); + //the call to the overloaded (or any) non-static member function definitely breaks the IRAM rule + // causing an exception when concurrently accessing the flash (or flash-filesystem) or wifi + //the reason is unknown but probably related with the compiler instantiation mechanism + //(note: defining the code of the [member] interrupt function outside the class declaration, + // and with IRAM flag does not avoid the crash) + //((I2S *)arg)->interrupt(); + + if(((I2S *)arg)->interruptStaticChild) + ((I2S *)arg)->interruptStaticChild(arg); } void I2S::reset() diff --git a/src/I2S/I2S.h b/src/I2S/I2S.h index 8213419..e898cea 100644 --- a/src/I2S/I2S.h +++ b/src/I2S/I2S.h @@ -52,8 +52,9 @@ class I2S void allocateDMABuffers(int count, int bytes); void deleteDMABuffers(); + void (*interruptStaticChild)(void *arg) = 0; + protected: - virtual void interrupt() = 0; virtual bool useInterrupt(); void setAPLLClock(long sampleRate, int bitCount); void setClock(long sampleRate, int bitCount, bool useAPLL = true); diff --git a/src/VGA/VGA14BitI.h b/src/VGA/VGA14BitI.h index 27254d6..12454c7 100644 --- a/src/VGA/VGA14BitI.h +++ b/src/VGA/VGA14BitI.h @@ -15,10 +15,11 @@ class VGA14BitI : public VGA, public GraphicsR5G5B4A2 { - public: + public: VGA14BitI(const int i2sIndex = 1) : VGA(i2sIndex) { + interruptStaticChild = &VGA14BitI::interrupt; } bool init(const Mode &mode, @@ -32,17 +33,10 @@ class VGA14BitI : public VGA, public GraphicsR5G5B4A2 G0Pin, G1Pin, G2Pin, G3Pin, G4Pin, B0Pin, B1Pin, B2Pin, B3Pin, hsyncPin, vsyncPin - }; + }; return VGA::init(mode, pinMap, 16, clockPin); } - bool init(const Mode &mode, const PinConfig &pinConfig) - { - int pins[16]; - pinConfig.fill14Bit(pins); - return VGA::init(mode, pins, 16, pinConfig.clock); - } - bool init(const Mode &mode, const int *redPins, const int *greenPins, const int *bluePins, const int hsyncPin, const int vsyncPin, const int clockPin = -1) { int pinMap[16]; @@ -58,6 +52,13 @@ class VGA14BitI : public VGA, public GraphicsR5G5B4A2 return VGA::init(mode, pinMap, 16, clockPin); } + bool init(const Mode &mode, const PinConfig &pinConfig) + { + int pins[16]; + pinConfig.fill14Bit(pins); + return VGA::init(mode, pins, 16, pinConfig.clock); + } + virtual void initSyncBits() { hsyncBitI = mode.hSyncPolarity ? 0x4000 : 0; @@ -99,19 +100,63 @@ class VGA14BitI : public VGA, public GraphicsR5G5B4A2 Graphics::show(vSync); } -protected: - virtual bool useInterrupt() + protected: + bool useInterrupt() { return true; }; - void interruptPixelLine(int y, unsigned long *pixels, unsigned long syncBits) + static void interrupt(void *arg); + + static void interruptPixelLine(int y, unsigned long *pixels, unsigned long syncBits, void *arg); +}; + + +void IRAM_ATTR VGA14BitI::interrupt(void *arg) +{ + VGA14BitI * staticthis = (VGA14BitI *)arg; + + unsigned long *signal = (unsigned long *)staticthis->dmaBufferDescriptors[staticthis->dmaBufferDescriptorActive].buffer(); + unsigned long *pixels = &((unsigned long *)staticthis->dmaBufferDescriptors[staticthis->dmaBufferDescriptorActive].buffer())[(staticthis->mode.hSync + staticthis->mode.hBack) / 2]; + unsigned long base, baseh; + if (staticthis->currentLine >= staticthis->mode.vFront && staticthis->currentLine < staticthis->mode.vFront + staticthis->mode.vSync) { - unsigned short *line = frontBuffer[y]; - for (int i = 0; i < mode.hRes / 2; i++) + baseh = (staticthis->hsyncBit | staticthis->vsyncBit) * 0x10001; + base = (staticthis->hsyncBitI | staticthis->vsyncBit) * 0x10001; + } + else + { + baseh = (staticthis->hsyncBit | staticthis->vsyncBitI) * 0x10001; + base = (staticthis->hsyncBitI | staticthis->vsyncBitI) * 0x10001; + } + for (int i = 0; i < staticthis->mode.hSync / 2; i++) + signal[i] = baseh; + for (int i = staticthis->mode.hSync / 2; i < (staticthis->mode.hSync + staticthis->mode.hBack) / 2; i++) + signal[i] = base; + + int y = (staticthis->currentLine - staticthis->mode.vFront - staticthis->mode.vSync - staticthis->mode.vBack) / staticthis->mode.vDiv; + if (y >= 0 && y < staticthis->mode.vRes) + staticthis->interruptPixelLine(y, pixels, base, arg); + else + for (int i = 0; i < staticthis->mode.hRes / 2; i++) { - //writing two pixels improves speed drastically (avoids memory reads) - pixels[i] = syncBits | (line[i * 2 + 1] & 0x3fff) | ((line[i * 2] & 0x3fff) << 16); + pixels[i] = base | (base << 16); } + for (int i = 0; i < staticthis->mode.hFront / 2; i++) + signal[i + (staticthis->mode.hSync + staticthis->mode.hBack + staticthis->mode.hRes) / 2] = base; + staticthis->currentLine = (staticthis->currentLine + 1) % staticthis->totalLines; + staticthis->dmaBufferDescriptorActive = (staticthis->dmaBufferDescriptorActive + 1) % staticthis->dmaBufferDescriptorCount; + if (staticthis->currentLine == 0) + staticthis->vSyncPassed = true; +} + +void IRAM_ATTR VGA14BitI::interruptPixelLine(int y, unsigned long *pixels, unsigned long syncBits, void *arg) +{ + VGA14BitI * staticthis = (VGA14BitI *)arg; + unsigned short *line = staticthis->frontBuffer[y]; + for (int i = 0; i < staticthis->mode.hRes / 2; i++) + { + //writing two pixels improves speed drastically (avoids memory reads) + pixels[i] = syncBits | (line[i * 2 + 1] & 0x3fff) | ((line[i * 2] & 0x3fff) << 16); } -}; \ No newline at end of file +} diff --git a/src/VGA/VGA3BitI.h b/src/VGA/VGA3BitI.h index fb169dd..a76a5c2 100644 --- a/src/VGA/VGA3BitI.h +++ b/src/VGA/VGA3BitI.h @@ -19,6 +19,7 @@ class VGA3BitI : public VGA, public GraphicsR1G1B1A1 VGA3BitI() //8 bit based modes only work with I2S1 : VGA(1) { + interruptStaticChild = &VGA3BitI::interrupt; } bool init(const Mode &mode, const int RPin, const int GPin, const int BPin, const int hsyncPin, const int vsyncPin, const int clockPin = -1) @@ -29,7 +30,7 @@ class VGA3BitI : public VGA, public GraphicsR1G1B1A1 BPin, -1, -1, -1, hsyncPin, vsyncPin - }; + }; return VGA::init(mode, pinMap, 8, clockPin); } @@ -87,53 +88,61 @@ class VGA3BitI : public VGA, public GraphicsR1G1B1A1 return true; }; - void interrupt() + static void interrupt(void *arg); + + static void interruptPixelLine(int y, unsigned long *pixels, unsigned long syncBits, void *arg); +}; + + +void IRAM_ATTR VGA3BitI::interrupt(void *arg) +{ + VGA3BitI * staticthis = (VGA3BitI *)arg; + + unsigned long *signal = (unsigned long *)staticthis->dmaBufferDescriptors[staticthis->dmaBufferDescriptorActive].buffer(); + unsigned long *pixels = &((unsigned long *)staticthis->dmaBufferDescriptors[staticthis->dmaBufferDescriptorActive].buffer())[(staticthis->mode.hSync + staticthis->mode.hBack) / 4]; + unsigned long base, baseh; + if (staticthis->currentLine >= staticthis->mode.vFront && staticthis->currentLine < staticthis->mode.vFront + staticthis->mode.vSync) { - unsigned long *signal = (unsigned long *)dmaBufferDescriptors[dmaBufferDescriptorActive].buffer(); - unsigned long *pixels = &((unsigned long *)dmaBufferDescriptors[dmaBufferDescriptorActive].buffer())[(mode.hSync + mode.hBack) / 4]; - unsigned long base, baseh; - if (currentLine >= mode.vFront && currentLine < mode.vFront + mode.vSync) - { - baseh = syncBits(true, true); - base = syncBits(false, true); - } - else - { - baseh = syncBits(true, false); - base = syncBits(false, false); - } - for (int i = 0; i < mode.hSync / 4; i++) - signal[i] = baseh; - for (int i = mode.hSync / 4; i < (mode.hSync + mode.hBack) / 4; i++) - signal[i] = base; - - int y = (currentLine - mode.vFront - mode.vSync - mode.vBack) / mode.vDiv; - if (y >= 0 && y < mode.vRes) - interruptPixelLine(y, pixels, base); - else - for (int i = 0; i < mode.hRes / 4; i++) - { - pixels[i] = base; - } - for (int i = 0; i < mode.hFront / 4; i++) - signal[i + (mode.hSync + mode.hBack + mode.hRes) / 4] = base; - currentLine = (currentLine + 1) % totalLines; - dmaBufferDescriptorActive = (dmaBufferDescriptorActive + 1) % dmaBufferDescriptorCount; - if (currentLine == 0) - vSync(); + baseh = (staticthis->hsyncBit | staticthis->vsyncBit) * 0x1010101; + base = (staticthis->hsyncBitI | staticthis->vsyncBit) * 0x1010101; } - - void interruptPixelLine(int y, unsigned long *pixels, unsigned long syncBits) + else { - unsigned char *line = frontBuffer[y]; - int j = 0; - for (int i = 0; i < mode.hRes / 4; i++) + baseh = (staticthis->hsyncBit | staticthis->vsyncBitI) * 0x1010101; + base = (staticthis->hsyncBitI | staticthis->vsyncBitI) * 0x1010101; + } + for (int i = 0; i < staticthis->mode.hSync / 4; i++) + signal[i] = baseh; + for (int i = staticthis->mode.hSync / 4; i < (staticthis->mode.hSync + staticthis->mode.hBack) / 4; i++) + signal[i] = base; + + int y = (staticthis->currentLine - staticthis->mode.vFront - staticthis->mode.vSync - staticthis->mode.vBack) / staticthis->mode.vDiv; + if (y >= 0 && y < staticthis->mode.vRes) + staticthis->interruptPixelLine(y, pixels, base, arg); + else + for (int i = 0; i < staticthis->mode.hRes / 4; i++) { - int p0 = (line[j] >> 0) & 7; - int p1 = (line[j++] >> 4) & 7; - int p2 = (line[j] >> 0) & 7; - int p3 = (line[j++] >> 4) & 7; - pixels[i] = syncBits | (p2 << 0) | (p3 << 8) | (p0 << 16) | (p1 << 24); + pixels[i] = base; } + for (int i = 0; i < staticthis->mode.hFront / 4; i++) + signal[i + (staticthis->mode.hSync + staticthis->mode.hBack + staticthis->mode.hRes) / 4] = base; + staticthis->currentLine = (staticthis->currentLine + 1) % staticthis->totalLines; + staticthis->dmaBufferDescriptorActive = (staticthis->dmaBufferDescriptorActive + 1) % staticthis->dmaBufferDescriptorCount; + if (staticthis->currentLine == 0) + staticthis->vSyncPassed = true; +} + +void IRAM_ATTR VGA3BitI::interruptPixelLine(int y, unsigned long *pixels, unsigned long syncBits, void *arg) +{ + VGA3BitI * staticthis = (VGA3BitI *)arg; + unsigned char *line = staticthis->frontBuffer[y]; + int j = 0; + for (int i = 0; i < staticthis->mode.hRes / 4; i++) + { + int p0 = (line[j] >> 0) & 7; + int p1 = (line[j++] >> 4) & 7; + int p2 = (line[j] >> 0) & 7; + int p3 = (line[j++] >> 4) & 7; + pixels[i] = syncBits | (p2 << 0) | (p3 << 8) | (p0 << 16) | (p1 << 24); } -}; +} diff --git a/src/VGA/VGA6BitI.h b/src/VGA/VGA6BitI.h index d140fad..d4264be 100644 --- a/src/VGA/VGA6BitI.h +++ b/src/VGA/VGA6BitI.h @@ -19,9 +19,10 @@ class VGA6BitI : public VGA, public GraphicsR2G2B2A2 VGA6BitI() //8 bit based modes only work with I2S1 : VGA(1) { + interruptStaticChild = &VGA6BitI::interrupt; } - bool init(Mode &mode, + bool init(const Mode &mode, const int R0Pin, const int R1Pin, const int G0Pin, const int G1Pin, const int B0Pin, const int B1Pin, @@ -33,7 +34,6 @@ class VGA6BitI : public VGA, public GraphicsR2G2B2A2 B0Pin, B1Pin, hsyncPin, vsyncPin }; - return VGA::init(mode, pinMap, 8, clockPin); } @@ -47,8 +47,7 @@ class VGA6BitI : public VGA, public GraphicsR2G2B2A2 pinMap[i + 4] = bluePins[i]; } pinMap[6] = hsyncPin; - pinMap[7] = vsyncPin; - return VGA::init(mode, pinMap, 8, clockPin); + pinMap[7] = vsyncPin; return VGA::init(mode, pinMap, 8, clockPin); } bool init(const Mode &mode, const PinConfig &pinConfig) @@ -105,53 +104,61 @@ class VGA6BitI : public VGA, public GraphicsR2G2B2A2 return true; }; - void interrupt() + static void interrupt(void *arg); + + static void interruptPixelLine(int y, unsigned long *pixels, unsigned long syncBits, void *arg); +}; + + +void IRAM_ATTR VGA6BitI::interrupt(void *arg) +{ + VGA6BitI * staticthis = (VGA6BitI *)arg; + + unsigned long *signal = (unsigned long *)staticthis->dmaBufferDescriptors[staticthis->dmaBufferDescriptorActive].buffer(); + unsigned long *pixels = &((unsigned long *)staticthis->dmaBufferDescriptors[staticthis->dmaBufferDescriptorActive].buffer())[(staticthis->mode.hSync + staticthis->mode.hBack) / 4]; + unsigned long base, baseh; + if (staticthis->currentLine >= staticthis->mode.vFront && staticthis->currentLine < staticthis->mode.vFront + staticthis->mode.vSync) { - unsigned long *signal = (unsigned long *)dmaBufferDescriptors[dmaBufferDescriptorActive].buffer(); - unsigned long *pixels = &((unsigned long *)dmaBufferDescriptors[dmaBufferDescriptorActive].buffer())[(mode.hSync + mode.hBack) / 4]; - unsigned long base, baseh; - if (currentLine >= mode.vFront && currentLine < mode.vFront + mode.vSync) - { - baseh = syncBits(true, true); - base = syncBits(false, true); - } - else - { - baseh = syncBits(true, false); - base = syncBits(false, false); - } - for (int i = 0; i < mode.hSync / 4; i++) - signal[i] = baseh; - for (int i = mode.hSync / 4; i < (mode.hSync + mode.hBack) / 4; i++) - signal[i] = base; - - int y = (currentLine - mode.vFront - mode.vSync - mode.vBack) / mode.vDiv; - if (y >= 0 && y < mode.vRes) - interruptPixelLine(y, pixels, base); - else - for (int i = 0; i < mode.hRes / 4; i++) - { - pixels[i] = base; - } - for (int i = 0; i < mode.hFront / 4; i++) - signal[i + (mode.hSync + mode.hBack + mode.hRes) / 4] = base; - currentLine = (currentLine + 1) % totalLines; - dmaBufferDescriptorActive = (dmaBufferDescriptorActive + 1) % dmaBufferDescriptorCount; - if (currentLine == 0) - vSync(); + baseh = (staticthis->hsyncBit | staticthis->vsyncBit) * 0x1010101; + base = (staticthis->hsyncBitI | staticthis->vsyncBit) * 0x1010101; } - - void interruptPixelLine(int y, unsigned long *pixels, unsigned long syncBits) + else { - unsigned char *line = frontBuffer[y]; - int j = 0; - for (int i = 0; i < mode.hRes / 4; i++) + baseh = (staticthis->hsyncBit | staticthis->vsyncBitI) * 0x1010101; + base = (staticthis->hsyncBitI | staticthis->vsyncBitI) * 0x1010101; + } + for (int i = 0; i < staticthis->mode.hSync / 4; i++) + signal[i] = baseh; + for (int i = staticthis->mode.hSync / 4; i < (staticthis->mode.hSync + staticthis->mode.hBack) / 4; i++) + signal[i] = base; + + int y = (staticthis->currentLine - staticthis->mode.vFront - staticthis->mode.vSync - staticthis->mode.vBack) / staticthis->mode.vDiv; + if (y >= 0 && y < staticthis->mode.vRes) + staticthis->interruptPixelLine(y, pixels, base, arg); + else + for (int i = 0; i < staticthis->mode.hRes / 4; i++) { - int p0 = (line[j] >> 0) & 7; - int p1 = (line[j++] >> 4) & 7; - int p2 = (line[j] >> 0) & 7; - int p3 = (line[j++] >> 4) & 7; - pixels[i] = syncBits | (p2 << 0) | (p3 << 8) | (p0 << 16) | (p1 << 24); + pixels[i] = base; } + for (int i = 0; i < staticthis->mode.hFront / 4; i++) + signal[i + (staticthis->mode.hSync + staticthis->mode.hBack + staticthis->mode.hRes) / 4] = base; + staticthis->currentLine = (staticthis->currentLine + 1) % staticthis->totalLines; + staticthis->dmaBufferDescriptorActive = (staticthis->dmaBufferDescriptorActive + 1) % staticthis->dmaBufferDescriptorCount; + if (staticthis->currentLine == 0) + staticthis->vSyncPassed = true; +} + +void IRAM_ATTR VGA6BitI::interruptPixelLine(int y, unsigned long *pixels, unsigned long syncBits, void *arg) +{ + VGA6BitI * staticthis = (VGA6BitI *)arg; + unsigned char *line = staticthis->frontBuffer[y]; + int j = 0; + for (int i = 0; i < staticthis->mode.hRes / 4; i++) + { + int p0 = (line[j++]) & 63; + int p1 = (line[j++]) & 63; + int p2 = (line[j++]) & 63; + int p3 = (line[j++]) & 63; + pixels[i] = syncBits | (p2 << 0) | (p3 << 8) | (p0 << 16) | (p1 << 24); } -}; +}