Go Down

Topic: Serial1 transmissions landing me in Dummy Handler loop (Read 249 times) previous topic - next topic

fostac

I'm working on a custom SAMD51 board similar to Adafruit's Metro M4 or Feather M4 and I need to move a few pins and serial ports around. Though when I try to change the pins used for Serial1 my program gets locked up in a cortex_handler.c empty function called Dummy_Handler. From what I can gather this may have something to do with the interrupt routines that Arduino's Serial implements, but I'm not sure how or why exactly this wouldn't be working. Looking up the call stack the program is interrupted during a delay inside the Arduino Serial library. Even stranger when modify the variant file similarly and compile for Sparkfun's SAMD51 Thing Plus I'm able to print to Serial1 with no issues.

I'm able to initialize Serial1 just fine with something like Serial1.begin(9600); though when I attempt to print or write I'm pushed to the Dummy_Handler.

Currently I'm trying to use SERCOM0 on pins PA08/PA09 and I have also tried SERCOM4 on PA12/PA13 with the same result. Does this sound familiar to anyone and is this Dummy Handler loop a generic fault?

I can share my variant files and anything else that could help if this is potentially helpful - thanks.

MartinL

Hi fostac,

Serial1 has already been defined by Adafruit's SAMD51 core code and is available on digital pins D0 and D1.

However additional ports can be created using spare SERCOM modules. Here's an example for the Adafruit Feather M4 that creates an additional serial port called Serial2 using SERCOM4, on pins A2 (Tx) and A3 (Rx):

Code: [Select]
#include "wiring_private.h"             // pinPeripheral() function

// Create Serial2 object
Uart Serial2 (&sercom4, A3, A2, SERCOM_RX_PAD_1, UART_TX_PAD_0);

void SERCOM4_0_Handler()                // Interrupt handler functions
{
  Serial2.IrqHandler();
}
void SERCOM4_1_Handler()
{
  Serial2.IrqHandler();
}
void SERCOM4_2_Handler()
{
  Serial2.IrqHandler();
}
void SERCOM4_3_Handler()
{
  Serial2.IrqHandler();
}
 
void setup() {
  Serial2.begin(115200);              // Open the Serial2 port at 115200 baud
 
  pinPeripheral(A2, PIO_SERCOM_ALT);  // Assign SERCOM functionality to A2
  pinPeripheral(A3, PIO_SERCOM_ALT);  // Assign SERCOM functionality to A3
}

void loop() {
  if (Serial2.available())            // Check if incoming data is available on A3
  {
    byte byteRead = Serial2.read();   // Read the most recent byte on A3
    Serial2.write(byteRead);          // Echo the byte back out on A2
  }
}

The code simply echos back text entered at the Arduino IDE console.

The key to selecting the correct SERCOM module is the multiplexing table in the SAMD51 datasheet. If the SERCOM module is in column C, use the PIO_SERCOM definition as an argument for the pinPeripheral() function:

Code: [Select]
pinPeripheral(12, PIO_SERCOM);  // Assign SERCOM functionality to D12
....where as if it's in column D, use PIO_SERCOM_ALT:

Code: [Select]
pinPeripheral(A2, PIO_SERCOM_ALT);  // Assign SERCOM functionality to A2
The other point to note, is that the SAMD51's serial port output assignments aren't quite as flexible as the SAMD21's, as the transmit pin must be on SERCOM/PAD[0].

fostac

Serial1 has already been defined by Adafruit's SAMD51 core code and is available on digital pins D0 and D1.
]

Maybe I don't understand the variant model then - are you saying Serial1 is defined somewhere above the board variant files? When I'm trying to modify the Serial1 pins I'm changing the pin definitions in g_APinDescription within variant.cpp to reflect the pins and corresponding SERCOMs I'd like to us. Typically I'll copy off a similar enough board like the metro_m4 variant and use that as a starting point.

So the D0/D1 definitions of the Metro M4:

Code: [Select]

// 0/1 - SERCOM/UART (Serial1)
{ PORTA, 23, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH3, TC4_CH1, EXTERNAL_INT_7 }, // RX: SERCOM3/PAD[1]
{ PORTA, 22, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH2, TC4_CH0, EXTERNAL_INT_6 }, // TX: SERCOM3/PAD[0]


would end up looking like this:

Code: [Select]

// 0/1 - SERCOM/UART (Serial1)
{ PORTA, 8, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NMI },
    { PORTA, 9, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_9 },


or something like this if I'm trying to use the alternative SERCOM functionality

Code: [Select]

// 0/1 - SERCOM/UART (Serial1)
{ PORTA, 8, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NMI },
    { PORTA, 9, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_9 },


Is Serial1 immutable for some reason?


MartinL

Hi fostac,

Quote
Is Serial1 immutable for some reason?
Well...yes and no.

If you go down to the bottom of the Metro M4's "variant.cpp" file, you'll see the line:

Code: [Select]
Uart Serial1( &sercom3, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ;
Adafruit has already created the Serial1 object. Obviously, you're free to delete this and create your own, but I'd question whether it's worth it? It's easier to simply create new additional serial ports: Serial2, Serial3 and Serial4.

The question is whether your custom board has its own copy of the core code, or if it's using the core code of an existing board, such as the Metro M4. If it's the latter, any subsequent updates from Adafruit will overwrite any changes you make to the core code, including the "variant" files.

fostac

I see, so to maybe shine a little more light on what the build process looks like here - I've copied off a full version of Adafruit's forked Arduinocore-SAMD and placed it in the hardware folder of my project. I'm using arduino-cli to reference the core files, including the variants and other arduino core files, to build a binary of my sketch. I then copy off a variant from the variants directory, add it to boards.txt and modify the copied variant files. Simple pin swaps like LED_BUILTIN's D13 and moving other SERCOMS seem to work well enough though when I attempt to swap Serial1 in particular I get sent to the Dummy Handler on print.

The modifications to the variant.cpp looks like this:

Code: [Select]

// 0/1 - SERCOM/UART (Serial1)
  //{ PORTB, 17, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH4, NOT_ON_TIMER, EXTERNAL_INT_1 }, // RX: SERCOM5/PAD[1]
  //{ PORTB, 16, PIO_SERCOM, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH5, NOT_ON_TIMER, EXTERNAL_INT_0 }, // TX: SERCOM5/PAD[0]
  { PORTA, 8, PIO_SERCOM_ALT, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NMI },
  { PORTA, 9, PIO_SERCOM_ALT, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_9 },

...

Uart Serial1( &sercom2, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ;


I've also tried to use other pins with the primary and alternate SERCOM combinations with no luck.

The intent with this whole build process is to sort of containerize all build files required to work on the sketch and generate a binary. Once it's all working I'll fork the adafruit core and maintain this board's variant in that fork.


MartinL

Hi fostac,

Your changes to the "variant.cpp" file look good.

Looking in the "variant.h" file, what SERCOM modules are SPI and I2C using? Just to verify that they're not using SERCOM2.

Go Up