From c1de5532aace791611ea47f27dd4200f161229e8 Mon Sep 17 00:00:00 2001 From: Dale Whinham Date: Thu, 2 Feb 2023 22:38:30 +0000 Subject: [PATCH] WIP: Pisound TX working, but not at correct clock TODO: Fix synth routing path --- Config.mk | 2 +- include/kernel.h | 4 +-- include/mt32pi.h | 6 ++-- include/pisound.h | 16 +++++++---- src/kernel.cpp | 1 + src/midiparser.cpp | 2 ++ src/mt32pi.cpp | 52 ++++++++++++++++++++++++++++------- src/pisound.cpp | 68 ++++++++++++++++++++++++++++++++++++---------- 8 files changed, 115 insertions(+), 36 deletions(-) diff --git a/Config.mk b/Config.mk index 143f76a..cde4e95 100644 --- a/Config.mk +++ b/Config.mk @@ -4,7 +4,7 @@ # Valid options: pi3, pi3-64, pi4, pi4-64 BOARD?=pi3-64 -HDMI_CONSOLE?=0 +HDMI_CONSOLE?=1 # Serial bootloader config SERIALPORT?=/dev/ttyUSB0 diff --git a/include/kernel.h b/include/kernel.h index 38b8ee8..8ee1095 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include "config.h" @@ -58,7 +58,7 @@ protected: FATFS m_SDFileSystem; CI2CMaster m_I2CMaster; - CSPIMaster m_SPIMaster; + CSPIMasterDMA m_SPIMaster; CGPIOManager m_GPIOManager; private: diff --git a/include/mt32pi.h b/include/mt32pi.h index 48ae0a5..4db25a6 100644 --- a/include/mt32pi.h +++ b/include/mt32pi.h @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include @@ -69,7 +69,7 @@ class CMT32Pi : CMultiCoreSupport, CPower, CMIDIParser, CAppleMIDIHandler, CUDPMIDIHandler { public: - CMT32Pi(CI2CMaster* pI2CMaster, CSPIMaster* pSPIMaster, CInterruptSystem* pInterrupt, CGPIOManager* pGPIOManager, CSerialDevice* pSerialDevice, CUSBHCIDevice* pUSBHCI); + CMT32Pi(CI2CMaster* pI2CMaster, CSPIMasterDMA* pSPIMaster, CInterruptSystem* pInterrupt, CGPIOManager* pGPIOManager, CSerialDevice* pSerialDevice, CUSBHCIDevice* pUSBHCI); virtual ~CMT32Pi() override; bool Initialize(bool bSerialMIDIAvailable = true); @@ -148,7 +148,7 @@ private: CActLED* m_pActLED; CI2CMaster* m_pI2CMaster; - CSPIMaster* m_pSPIMaster; + CSPIMasterDMA* m_pSPIMaster; CInterruptSystem* m_pInterrupt; CGPIOManager* m_pGPIOManager; CSerialDevice* m_pSerial; diff --git a/include/pisound.h b/include/pisound.h index dda3442..69bf008 100644 --- a/include/pisound.h +++ b/include/pisound.h @@ -25,23 +25,28 @@ #include #include -#include +#include +#include +#include #include #include "ringbuffer.h" -class CPisound +class CPisound : protected CTask { public: using TMIDIReceiveHandler = void (*)(const u8* pData, size_t nSize); - CPisound(CSPIMaster* pSPIMaster, CGPIOManager* pGPIOManager, unsigned nSamplerate); - ~CPisound(); + CPisound(CSPIMasterDMA* pSPIMaster, CGPIOManager* pGPIOManager, unsigned nSamplerate); + virtual ~CPisound() override; bool Initialize(); void RegisterMIDIReceiveHandler(TMIDIReceiveHandler pHandler) { m_pReceiveHandler = pHandler; } size_t SendMIDI(const u8* pData, size_t nSize); + virtual void Run() override; + void DoTransfer(); + private: u16 Transfer16(u16 nValue) const; size_t ReadBytes(u8* pOutBuffer, size_t nSize) const; @@ -53,7 +58,8 @@ private: static constexpr size_t MaxIDStringLength = 25; static constexpr size_t MaxVersionStringLength = 6; - CSPIMaster* m_pSPIMaster; + CSpinLock m_Lock; + CSPIMasterDMA* m_pSPIMaster; unsigned m_nSamplerate; CGPIOPin m_SPIReset; diff --git a/src/kernel.cpp b/src/kernel.cpp index e9d2f99..08ba180 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -42,6 +42,7 @@ CKernel::CKernel(void) m_SDFileSystem{}, m_I2CMaster(1, true), + m_SPIMaster(&mInterrupt), m_GPIOManager(&mInterrupt), m_MT32Pi(&m_I2CMaster, &m_SPIMaster, &mInterrupt, &m_GPIOManager, &m_Serial, &m_USBHCI) diff --git a/src/midiparser.cpp b/src/midiparser.cpp index d92a742..092797a 100644 --- a/src/midiparser.cpp +++ b/src/midiparser.cpp @@ -41,6 +41,8 @@ void CMIDIParser::ParseMIDIBytes(const u8* pData, size_t nSize, bool bIgnoreNote { u8 nByte = pData[i]; + //CLogger::Get()->Write(MIDIParserName, LogNotice, "0x%02X", nByte); + // System Real-Time message - single byte, handle immediately // Can appear anywhere in the stream, even in between status/data bytes if (nByte >= 0xF8) diff --git a/src/mt32pi.cpp b/src/mt32pi.cpp index 7fe5085..fbe61ee 100644 --- a/src/mt32pi.cpp +++ b/src/mt32pi.cpp @@ -59,7 +59,7 @@ enum class TCustomSysExCommand : u8 CMT32Pi* CMT32Pi::s_pThis = nullptr; -CMT32Pi::CMT32Pi(CI2CMaster* pI2CMaster, CSPIMaster* pSPIMaster, CInterruptSystem* pInterrupt, CGPIOManager* pGPIOManager, CSerialDevice* pSerialDevice, CUSBHCIDevice* pUSBHCI) +CMT32Pi::CMT32Pi(CI2CMaster* pI2CMaster, CSPIMasterDMA* pSPIMaster, CInterruptSystem* pInterrupt, CGPIOManager* pGPIOManager, CSerialDevice* pSerialDevice, CUSBHCIDevice* pUSBHCI) : CMultiCoreSupport(CMemorySystem::Get()), CMIDIParser(), @@ -712,6 +712,29 @@ void CMT32Pi::OnAppleMIDIDisconnect(const CIPAddress* pIPAddress, const char* pN LCDLog(TLCDLogType::Notice, "%s disconnected!", pName); } +void PrintRouting(const char* pDevice, u8 nRouting) +{ + char Buffer[256]; + sprintf(Buffer, " - %-10s ->", pDevice); + + if (nRouting == TMIDIRoutingDest::None) + { + strcat(Buffer, " none"); + LOGNOTE(Buffer); + return; + } + + if (nRouting & TMIDIRoutingDest::Synth) strncat(Buffer, " synth", sizeof(Buffer)); + if (nRouting & TMIDIRoutingDest::GPIO) strncat(Buffer, " gpio", sizeof(Buffer)); + if (nRouting & TMIDIRoutingDest::Pisound) strncat(Buffer, " pisound", sizeof(Buffer)); + if (nRouting & TMIDIRoutingDest::USBMIDI) strncat(Buffer, " usb_midi", sizeof(Buffer)); + if (nRouting & TMIDIRoutingDest::USBSerial) strncat(Buffer, " usb_serial", sizeof(Buffer)); + if (nRouting & TMIDIRoutingDest::RTP) strncat(Buffer, " rtp", sizeof(Buffer)); + if (nRouting & TMIDIRoutingDest::UDP) strncat(Buffer, " udp", sizeof(Buffer)); + + LOGNOTE(Buffer); +} + bool CMT32Pi::ParseCustomSysEx(const u8* pData, size_t nSize) { if (nSize < 4) @@ -745,6 +768,15 @@ bool CMT32Pi::ParseCustomSysEx(const u8* pData, size_t nSize) case 4: m_pConfig->MIDIRouteRTP = nRouting; break; case 5: m_pConfig->MIDIRouteUDP = nRouting; break; } + + LOGNOTE("MIDI routing setup:"); + PrintRouting("gpio", m_pConfig->MIDIRouteGPIO); + PrintRouting("usb_midi", m_pConfig->MIDIRouteUSBMIDI); + PrintRouting("usb_serial", m_pConfig->MIDIRouteUSBSerial); + PrintRouting("pisound", m_pConfig->MIDIRoutePisound); + PrintRouting("rtp", m_pConfig->MIDIRouteRTP); + PrintRouting("udp", m_pConfig->MIDIRouteUDP); + return true; } @@ -1032,7 +1064,7 @@ void CMT32Pi::ProcessMIDIRouting(const TMIDIRouting& Routing, const u8* pData, s } // Send to GPIO UART - if (Routing & GPIO && m_bSerialMIDIEnabled) + if ((Routing & GPIO) && m_bSerialMIDIEnabled) { const int nSendResult = m_pSerial->Write(pData, nSize); if (nSendResult < 0 || static_cast(nSendResult) != nSize) @@ -1043,44 +1075,44 @@ void CMT32Pi::ProcessMIDIRouting(const TMIDIRouting& Routing, const u8* pData, s } // Send to Pisound - if (Routing & Pisound && m_pPisound) + if ((Routing & Pisound) && m_pPisound) { if (m_pPisound->SendMIDI(pData, nSize) != nSize) { - m_pLogger->Write(MT32PiName, LogError, "Pisound MIDI TX error"); + LOGERR("Pisound MIDI TX error"); LCDLog(TLCDLogType::Error, "Pisound MIDI TX error!"); } } // Send to USB MIDI - if (Routing & USBMIDI && m_pUSBMIDIDevice) + if ((Routing & USBMIDI) && m_pUSBMIDIDevice) { if (m_pUSBMIDIDevice->SendPlainMIDI(0, pData, nSize) == false) { - m_pLogger->Write(MT32PiName, LogError, "USB MIDI TX error"); + LOGERR("USB MIDI TX error"); LCDLog(TLCDLogType::Error, "USB MIDI TX error!"); } } // Send to USB serial - if (Routing & USBSerial && m_pUSBSerialDevice) + if ((Routing & USBSerial) && m_pUSBSerialDevice) { const int nSendResult = m_pUSBSerialDevice->Write(pData, nSize); if (nSendResult < 0 || static_cast(nSendResult) != nSize) { - m_pLogger->Write(MT32PiName, LogError, "USB serial TX error %d (wanted to send %d bytes)", nSendResult, nSize); + LOGERR("USB serial TX error %d (wanted to send %d bytes)", nSendResult, nSize); LCDLog(TLCDLogType::Error, "USB serial TX error!"); } } // Send to AppleMIDI - if (Routing & RTP && m_pAppleMIDIParticipant) + if ((Routing & RTP) && m_pAppleMIDIParticipant) { // TODO: AppleMIDIParticipant has no transmit functionality } // Send to UDP MIDI - if (Routing & UDP && m_pUDPMIDIReceiver) + if ((Routing & UDP) && m_pUDPMIDIReceiver) { // TODO: UDPMIDIReceiver has no transmit functionality } diff --git a/src/pisound.cpp b/src/pisound.cpp index 3690378..f91c295 100644 --- a/src/pisound.cpp +++ b/src/pisound.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -31,8 +32,8 @@ LOGMODULE("pisound"); constexpr u8 SPIChipSelect = 0; -constexpr u8 SPIDelayMicroseconds = 10; -constexpr u32 SPIClockSpeed = 150000; +// FIXME: Linux driver works at 150000Hz, but here we get data corruption hence lower clock speed - investigate +constexpr u32 SPIClockSpeed = 15000; constexpr u8 SPITransferSize = 4; constexpr u8 GPIOButton = 17; @@ -48,8 +49,10 @@ constexpr u8 GPIOSPIDataAvailable = 25; // Based on: https://github.com/raspberrypi/linux/blob/rpi-5.4.y/sound/soc/bcm/pisound.c // https://github.com/raspberrypi/linux/blob/rpi-5.4.y/arch/arm/boot/dts/overlays/pisound-overlay.dts -CPisound::CPisound(CSPIMaster* pSPIMaster, CGPIOManager* pGPIOManager, unsigned nSamplerate) - : m_pSPIMaster(pSPIMaster), +CPisound::CPisound(CSPIMasterDMA* pSPIMaster, CGPIOManager* pGPIOManager, unsigned nSamplerate) + : CTask(TASK_STACK_SIZE, true), + m_Lock(IRQ_LEVEL), + m_pSPIMaster(pSPIMaster), m_nSamplerate(nSamplerate), m_SPIReset(GPIOSPIReset, TGPIOMode::GPIOModeOutput), @@ -80,6 +83,8 @@ CPisound::~CPisound() m_OversamplingRatio0.SetMode(TGPIOMode::GPIOModeInputPullDown); m_OversamplingRatio1.SetMode(TGPIOMode::GPIOModeInputPullDown); m_OversamplingRatio2.SetMode(TGPIOMode::GPIOModeInputPullDown); + + Terminate(); } bool CPisound::Initialize() @@ -106,7 +111,6 @@ bool CPisound::Initialize() } // Setup SPI - m_pSPIMaster->SetCSHoldTime(SPIDelayMicroseconds); m_pSPIMaster->SetClock(SPIClockSpeed); // Reset the SPI device @@ -131,15 +135,18 @@ bool CPisound::Initialize() LOGNOTE("Firmware version: %s", m_FirmwareVersion); LOGNOTE("Hardware version: %s", m_HardwareVersion); + Start(); + return true; } size_t CPisound::SendMIDI(const u8* pData, size_t nSize) { - // TODO - m_MIDITxBuffer.Enqueue(pData, nSize); - SPITask(); - return nSize; + // Wake up task + if (IsSuspended()) + Resume(); + + return m_MIDITxBuffer.Enqueue(pData, nSize); } u16 CPisound::Transfer16(u16 nTxValue) const @@ -149,7 +156,7 @@ u16 CPisound::Transfer16(u16 nTxValue) const SPITxBuffer[0] = nTxValue >> 8; SPITxBuffer[1] = nTxValue & 0xFF; - if (m_pSPIMaster->WriteRead(SPIChipSelect, SPITxBuffer, SPIRxBuffer, sizeof(SPIRxBuffer)) < 0) + if (m_pSPIMaster->WriteReadSync(SPIChipSelect, SPITxBuffer, SPIRxBuffer, sizeof(SPIRxBuffer)) < 0) return 0; return (SPIRxBuffer[0] << 8) | SPIRxBuffer[1]; @@ -246,11 +253,16 @@ void CPisound::SetOSRPins(unsigned bRatio1, unsigned bRatio2, unsigned bRatio3) void CPisound::DataAvailableInterruptHandler(void* pUserData) { CPisound* pThis = static_cast(pUserData); - pThis->SPITask(); + if (pThis->IsSuspended()) + pThis->Resume(); } -void CPisound::SPITask() +void CPisound::DoTransfer() { + bool bHadData = false; + + m_Lock.Acquire(); + do { size_t nMIDIRxBytes = 0; @@ -260,6 +272,8 @@ void CPisound::SPITask() u8 SPIRxBuffer[SPITransferSize]; u8 SPITxBuffer[SPITransferSize]; + + bHadData = false; memset(SPIRxBuffer, 0, sizeof(SPIRxBuffer)); memset(SPITxBuffer, 0, sizeof(SPITxBuffer)); @@ -272,15 +286,39 @@ void CPisound::SPITask() } // Extract incoming MIDI bytes from SPI packet - m_pSPIMaster->WriteRead(SPIChipSelect, SPITxBuffer, SPIRxBuffer, sizeof(SPIRxBuffer)); - for (size_t i = 0; i < sizeof(SPIRxBuffer); i += 2) + if (m_pSPIMaster->WriteReadSync(SPIChipSelect, SPITxBuffer, SPIRxBuffer, SPITransferSize) != SPITransferSize) + { + LOGERR("SPI transfer failed"); + continue; + } + + for (size_t i = 0; i < SPITransferSize; i += 2) { if (SPIRxBuffer[i]) + { MIDIRxBuffer[nMIDIRxBytes++] = SPIRxBuffer[i + 1]; + bHadData = true; + } } // Pass MIDI bytes on to handler if (nMIDIRxBytes && m_pReceiveHandler) m_pReceiveHandler(MIDIRxBuffer, nMIDIRxBytes); - } while (m_DataAvailable.Read() == HIGH || !m_MIDITxBuffer.IsEmpty()); + } while (bHadData || !m_MIDITxBuffer.IsEmpty() || m_DataAvailable.Read() == HIGH); + + m_Lock.Release(); +} + +void CPisound::Run() +{ + CScheduler* const pScheduler = CScheduler::Get(); + + while (true) + { + DoTransfer(); + Suspend(); + + // Allow other tasks to run + pScheduler->Yield(); + } }