1212 See the License for the specific language governing permissions and
1313 limitations under the License.
1414*/
15- // GDB debugging of the Arduino Portenta-H7 over a serial connection.
15+ // GDB Kernel debugging of the Arduino Portenta-H7 over a serial UART connection.
1616#include " DebugSerial.h"
1717extern " C" {
1818 #include < core/mri.h>
@@ -55,26 +55,13 @@ static DebugSerial* g_pDebugSerial = NULL;
5555// Will be setting initial breakpoint on setup() routine.
5656void setup ();
5757
58- // Forward Function Declarations
59- static uint32_t readRegisterFromContextBuffer (Buffer* pBuffer, uint32_t regIndex);
60- static void writeRegisterToContextBuffer (Buffer* pBuffer, uint32_t regIndex, uint32_t regValue);
61-
58+ // The debugger uses this handler to catch faults, debug events, etc.
59+ extern " C" void mriExceptionHandler (void );
6260
63- DebugSerial::DebugSerial (HardwareSerial& serial, IRQn_Type irq, uint32_t baudRate, bool breakInSetup) :
64- _pContextBuffer(NULL ), _commIsr(NULL ), _serial(serial), _contextBufferSize(0 ), _baudRate(baudRate),
65- _irq(irq), _breakInSetup(breakInSetup)
66- {
67- construct ();
68- }
6961
70- DebugSerial::DebugSerial (HardwareSerial& serial, IRQn_Type irq) :
71- _pContextBuffer(NULL ), _commIsr(NULL ), _serial(serial), _contextBufferSize(0 ), _baudRate(0 ),
72- _irq(irq), _breakInSetup(false )
62+ DebugSerial::DebugSerial (PinName txPin, PinName rxPin, IRQn_Type irq, uint32_t baudRate, bool breakInSetup /* =true*/ ) :
63+ _serial(txPin, rxPin, baudRate), _irq(irq), _breakInSetup(breakInSetup)
7364{
74- construct ();
75- }
76-
77- void DebugSerial::construct () {
7865 // Just return without doing anything if the singleton has already been initialized.
7966 // This ends up using the first initialized DebugSerial object.
8067 if (g_pDebugSerial != NULL ) {
@@ -84,14 +71,10 @@ void DebugSerial::construct() {
8471
8572 mriInit (" " );
8673
87- if (_baudRate != 0 ) {
88- callSerialBeginFromSetup ();
89- }
74+ setupStopInSetup ();
9075}
9176
92- void DebugSerial::callSerialBeginFromSetup () {
93- _contextBufferSize = Platform_GetPacketBufferSize ();
94- _pContextBuffer = new char [_contextBufferSize];
77+ void DebugSerial::setupStopInSetup () {
9578 mriCore_SetTempBreakpoint ((uint32_t )setup, justEnteredSetupCallback, NULL );
9679}
9780
@@ -100,66 +83,13 @@ int DebugSerial::justEnteredSetupCallback(void* pv){
10083}
10184
10285int DebugSerial::justEnteredSetup () {
103- Buffer buffer;
104-
105- // Get current register context. Save away the contents of the registers in the context that we want to modify to
106- // setup for a call to g_pDebugSerial->initSerial().
107- Buffer_Init (&buffer, _pContextBuffer, _contextBufferSize);
108- Platform_CopyContextToBuffer (&buffer);
109- _lrOrig = readRegisterFromContextBuffer (&buffer, 14 );
110- _pcOrig = readRegisterFromContextBuffer (&buffer, 15 );
111-
112- uint32_t lr = (uint32_t )setup;
113- uint32_t pc = (uint32_t )_initSerial;
114- writeRegisterToContextBuffer (&buffer, 14 , lr);
115- writeRegisterToContextBuffer (&buffer, 15 , pc);
116- Buffer_Reset (&buffer);
117- Platform_CopyContextFromBuffer (&buffer);
118-
119- mriCore_SetTempBreakpoint ((uint32_t )setup, justReturnedFromInitSerialCallback, NULL );
120-
121- // Return 1 to indicate that we want to resume execution.
122- return 1 ;
123- }
124-
125- static uint32_t readRegisterFromContextBuffer (Buffer* pBuffer, uint32_t regIndex) {
126- uint32_t regValue = 0 ;
127- uint8_t * pCurr = (uint8_t *)®Value;
128-
129- pBuffer->pCurrent = pBuffer->pStart + 8 * regIndex;
130- for (size_t i = 0 ; i < sizeof (regValue) ; i++) {
131- *pCurr++ = Buffer_ReadByteAsHex (pBuffer);
132- }
133- return regValue;
134- }
135-
136- static void writeRegisterToContextBuffer (Buffer* pBuffer, uint32_t regIndex, uint32_t regValue) {
137- uint8_t * pCurr = (uint8_t *)®Value;
138-
139- pBuffer->pCurrent = pBuffer->pStart + 8 * regIndex;
140- for (size_t i = 0 ; i < sizeof (regValue) ; i++) {
141- Buffer_WriteByteAsHex (pBuffer, *pCurr++);
142- }
143- }
144-
145- int DebugSerial::justReturnedFromInitSerialCallback (void * pv) {
146- return g_pDebugSerial->justReturnedFromInitSerial ();
147- }
148-
149- int DebugSerial::justReturnedFromInitSerial () {
150- Buffer buffer;
151-
152- // Restore the registers to the way that they were before we called g_pDebugSerial->initSerial().
153- Buffer_Init (&buffer, _pContextBuffer, _contextBufferSize);
154- writeRegisterToContextBuffer (&buffer, 14 , _lrOrig);
155- writeRegisterToContextBuffer (&buffer, 15 , _pcOrig);
156- Buffer_Reset (&buffer);
157- Platform_CopyContextFromBuffer (&buffer);
86+ initSerial ();
15887
15988 // Return 0 to indicate that we want to halt execution at the beginning of setup() or 1 to not force a halt.
16089 return _breakInSetup ? 0 : 1 ;
16190}
16291
92+
16393DebugSerial::~DebugSerial () {
16494 // IMPORTANT NOTE: You are attempting to destroy the connection to GDB which isn't allowed.
16595 // Don't allow your DebugSerial object to go out of scope like this.
@@ -168,56 +98,33 @@ DebugSerial::~DebugSerial() {
16898 // Loop forever.
16999 }
170100}
101+
171102void DebugSerial::setSerialPriority (uint8_t priority) {
172103 mriCortexMSetPriority (_irq, priority, 0 );
173104}
174105
175- void DebugSerial::_initSerial () {
176- g_pDebugSerial->initSerial ();
177- delay (STARTUP_DELAY_MSEC);
178- }
179-
180106void DebugSerial::initSerial () {
181- _serial.begin (_baudRate);
182- setSerialPriority (0 );
183107
184108 // Hook communication port ISR to allow debug monitor to be awakened when GDB sends a command.
185- _commIsr = (IsrFunctionPtr) NVIC_GetVector (_irq);
186- NVIC_SetVector (_irq, (uint32_t )commInterruptHook);
187- }
188-
189- void DebugSerial::commInterruptHook (void ) {
190- g_pDebugSerial->pendDebugMonAndRunCommIsr ();
191- }
192-
193- void DebugSerial::pendDebugMonAndRunCommIsr (void ) {
194- _commIsr ();
195- if (_serial.available ()) {
196- // Pend a halt into the debug monitor if there is now data from GDB ready to be read by it.
197- setMonitorPending ();
198- }
109+ _serial.attach (mriExceptionHandler);
110+ setSerialPriority (2 );
111+ NVIC_SetVector (_irq, (uint32_t )mriExceptionHandler);
199112}
200113
201114uint32_t DebugSerial::hasReceiveData (void ) {
202- handleAnyPendingCommInterrupts ();
203- return _serial.available ();
204- }
205-
206- void DebugSerial::handleAnyPendingCommInterrupts () {
207- if (NVIC_GetPendingIRQ (_irq)) {
208- _commIsr ();
209- NVIC_ClearPendingIRQ (_irq);
210- }
115+ return _serial.readable ();
211116}
212117
213118int DebugSerial::receiveChar (void ) {
214119 while (!hasReceiveData ()) {
215120 }
216- return _serial.read ();
121+ uint8_t byte;
122+ _serial.read (&byte, 1 );
123+ return byte;
217124}
218125
219126void DebugSerial::sendChar (int character) {
220- _serial.write (character);
127+ _serial.write (& character, 1 );
221128}
222129
223130
@@ -227,9 +134,6 @@ void DebugSerial::sendChar(int character) {
227134// Global Platform_* functions needed by MRI to initialize and communicate with MRI.
228135// These functions will perform most of their work through the DebugSerial singleton.
229136// ---------------------------------------------------------------------------------------------------------------------
230- // The debugger uses this handler to catch faults, debug events, etc.
231- extern " C" void mriExceptionHandler (void );
232-
233137struct SystemHandlerPriorities {
234138 uint8_t svcallPriority;
235139 uint8_t pendsvPriority;
@@ -244,19 +148,18 @@ static void switchFaultHandlersToDebugger();
244148
245149extern " C" void Platform_Init (Token* pParameterTokens) {
246150 SystemHandlerPriorities origPriorities = getSystemHandlerPrioritiesBeforeMriModifiesThem ();
247- uint8_t debugMonPriority = 1 ;
151+ uint8_t debugMonPriority = 2 ;
248152
249153 __try
250154 mriCortexMInit ((Token*)pParameterTokens, debugMonPriority, WAKEUP_PIN_IRQn);
251155 __catch
252156 __rethrow;
253157
254- // UNDONE: Might want to always keep the USB handler at elevated priority.
255- // Set interrupt used by serial comms (UART or USB) at highest priority .
256- // Set DebugMonitor interrupt at next highest priority.
158+ // USB defaults to a priority of 1, keep that as highest priority interrupt so that it can respond to PC requests
159+ // while kernel debugging .
160+ // Set interrupts used by UART serial comms and DebugMonitor at next highest priority.
257161 // Set all other external interrupts lower than both serial comms and DebugMonitor.
258162 restoreSystemHandlerPriorities (&origPriorities);
259- g_pDebugSerial->setSerialPriority (0 );
260163
261164 switchFaultHandlersToDebugger ();
262165}
0 commit comments