chipKIT® Development Platform

Inspired by Arduino™

Using DSPI + Hardware serial input crashes my Max32...

Created Thu, 20 Sep 2012 22:42:27 +0000 by rasmadrak


rasmadrak

Thu, 20 Sep 2012 22:42:27 +0000

Hi there,

My Chipkit has started behaving really weird - everytime I try to read from any hardware serial port the board crashes, be it USB serial input from MPIDE or actual serial data from another card. Serial out from the Chipkit works perfectly. Serial in to the board has worked before (but it was a couple of months ago I tested last).

Has anyone experienced this before? What could be the issue? Could it be caused by a library update?

Or... is my board simply broken?


rasmadrak

Fri, 21 Sep 2012 19:35:44 +0000

This is regardless if Serial, Serial1, Serial2, Serial3 is used.

Anyone with experience of this..?


WestfW

Sun, 23 Sep 2012 06:38:47 +0000

It is pretty easy for this to happen if you're reading serial data into an array, and exceed the actual limits of the array. The exact failure modes can vary from program to program depending on exactly what is in the area of memory that you overwrite.

Post a simple code example for further analysis. And define "the board crashes." I assume it's not sending a hex dump to the line printer with abend codes attached...


rasmadrak

Tue, 09 Oct 2012 12:25:13 +0000

Hi there! Sorry for late reply, been out of country for a couple of weeks.

As soon as Serial.read() is used the board crashes. That's before even loading into any kind of array etc. No matter how I do things it crashes as soon as a read-command is issued. By crashing I mean that it stops doing anything at all. No reset/reboot, just frozen.


EmbeddedMan

Wed, 10 Oct 2012 00:18:52 +0000

What chipKIT board are you using? And have you tried the latest MPIDE build? Also, if you could post your sketch that causes the crash, I can try to duplicate the problem on my end.

*Brian


rasmadrak

Thu, 11 Oct 2012 12:09:47 +0000

Yes, the latest MPIDE build is being used.

I will try a lightweight program to check if there's something in my code that "kills" it. I have increased the heap/stack sizes in my current code and I don't remember if I've tried a hardware serial only program since then. Hopefully I'll be able to test this soon and post my findings.

Thanks again!


rasmadrak

Thu, 11 Oct 2012 21:31:39 +0000

Ok, I've loaded the simplest possible blinking light with Serial.read() and it does work. I've also tried resizing the heap and stack and that works fine too, so it must be something else in my code.

I can't figure out for the life of me what it could be thou, but I guess I'll have to do a little trial and error...

Thanks for your time and help! :)


rasmadrak

Thu, 11 Oct 2012 21:48:54 +0000

Hmm. It seems that the DSPI-library is crashing the Serial input for some reason. :/

Merely including the DSPI.h in the perfectly functioning sketch "crashes" the Max32 upon recieving serial input. Including the SPI-library does not cause a crash.

This is also one of the changes I've done (gone from SPI to DSPI) lately and is most likely the problem.

Any clues?


rasmadrak

Fri, 12 Oct 2012 08:59:32 +0000

Or do I have to include WProgram.h manually in my sketch before loading the DSPI.h?

(The SPI.h does not require this in any case)


rasmadrak

Sun, 14 Oct 2012 18:34:31 +0000

Is it possible for anyone with a Max32 to try including the DSPI.h library and reading hardware serial input?

It would be MUCH appreciated to know if my board/library/hardware is broken or if there's indeed a conflict in the library somewhere.

Thanks in advance!


Baltasar

Sun, 14 Oct 2012 19:30:14 +0000

Hi, just give me the test sketch you want me run and I tell you how it goes.


rasmadrak

Mon, 15 Oct 2012 22:23:15 +0000

Thanks!

Here's the simple test sketch that crashes everytime:

#include <DSPI.h>  //if commented out, this scetch runs without problems.

void setup() {                
  // initialize the digital pin as an output.
  // Pin 13 has an LED connected on most Arduino boards:
  pinMode(13, OUTPUT);     
  Serial.begin(115200);
}

void loop() {  
  if (Serial.available()) 
      Serial.println(Serial.read());  //crashpoint if DSPI.h is included. (read() crashes it )
  
  digitalWrite(13, HIGH);   // set the LED on
  delay(1000);              // wait for a second
  digitalWrite(13, LOW);    // set the LED off
  delay(1000);              // wait for a second
}

This is the example blink sketch with the added DSPI.h row and Serial rows.


Baltasar

Tue, 16 Oct 2012 01:08:11 +0000

Yap it crashes !!!

If I don't type anything + ENTER on the serial monitor window the led flashs ok, but as soon I type one single character... puff, green led stops.

I have to reset or power off and on again the board so the led starts blinking again.

I'm using the mpide-0023-windows-20120903 version.


rasmadrak

Tue, 16 Oct 2012 19:38:57 +0000

That's good (...) news! :) Now I guess we need a little Digilent love to cure this bug...

Thanks for your time and help!

Calling Gene Apperson... :)


GeneApperson

Tue, 16 Oct 2012 21:01:29 +0000

Oops....

I hate it when people find bugs in my code :)

I'll look into it. If just including the library and not actually calling any of the functions is causing a problem, I'm thinking it may be some kind of interrupt conflict.

Gene Apperson Digilent


GeneApperson

Tue, 16 Oct 2012 21:46:11 +0000

OK... I understand the problem.... fixing it is more problematic.

The problem comes in from the fact that the serial controllers in the MX5/6/7 devices are different than in the MX3/4 devices. In the MX3/4, there are separate serial controllers for UART and SPI ports. In the MX5/6/7 devices, the same serial controllers are used for both UARTs and SPI ports (& I2C ports).

In consequence of this, the UARTs and SPI ports on the Max32 share the same set of interrupt vectors. On the Uno32 they have different interrupt vectors. I developed the DSPI library on a Uno32, and clearly didn't test it enough on the Max32.

When you include the DSPI library, it installs a set of interrupt service routines for the same interrupt vectors as the HardwareSerial UARTs use. Since HardwareSerial uses interrupt driven I/O on the input side, what is probably happening is that the wrong ISR (the DSPI ISR) is actually receiving the interrupt. Since it hasn't been initialized, the system crashes.

If you're not using interrupt driven I/O for DSPI, you can work around the problem, by removing the definition for the DSPI ISRs at the bottom of DSPI.cpp. I just ran your example sketch. With the DSPI ISRs in place it crashes. After I removed the ISR definitions from DSPI.cpp, it no longer crashes. BTW: I didn't delete the ISR definitions, I just #ifdef'd them out. You could also just remove the ISR definition for the interrupt used by HardwareSerial object you are trying to use. The Serial object on the Max32 uses UART1, which conflicts with SPI3, which is used by DSPI2.

Unfortunately, to fix this properly is going to require implemeting an interrupt vector management subsystem in the core of the MPIDE runtime. This is something that I have been thinking about, and even started to implement several months ago, but got sidetracked onto other things. Clearly, I'm going to need to resurrect this and complete it.

I don't know how long this will take, but it will be a pretty major architectural change at the core of the system.

Gene Apperson Digilent


mhanuel

Wed, 17 Oct 2012 02:05:08 +0000

Hello Gene,

I think this bug is nothing but new, just see http://www.chipkit.org/forum/viewtopic.php?f=7&t=928

I am using DSPI.h for replacing the SD2Card.cpp bit bang routines. I am not really sure whether or not I am using interrupt driven I/O. For example, to receive I just do data = spi.transfer(0xFF);

In any case, another workaround I have found that works for me so far is to move the vectors conflict to another peripheral in my case I am using Serial, Serial1 and Serial2 so I move DSPI3 vectors which conflicts with SPI4 which indeed points to UART2 vectors, I move to I2C2 vector.

Something like this on Board_Defs.h line 372.

#define _DSPI2_BASE _CAN1_BASE_ADDRESS//_SPI3_BASE_ADDRESS #define _DSPI2_ERR_IRQ _CAN1_IRQ//_SPI3_ERR_IRQ #define _DSPI2_RX_IRQ _CAN1_IRQ//_SPI3_RX_IRQ #define _DSPI2_TX_IRQ _CAN1_IRQ//_SPI3_TX_IRQ #define _DSPI2_VECTOR _CAN_1_VECTOR//_SPI_3_VECTOR #define _DSPI2_IPL_ISR _CAN1_IPL_ISR//_SPI3_IPL_ISR #define _DSPI2_IPL _CAN1_IPL_IPC//_SPI3_IPL_IPC #define _DSPI2_SPL _CAN1_SPL_IPC //_SPI3_SPL_IPC

#define _DSPI3_BASE _I2C2A_BASE_ADDRESS //_SPI4_BASE_ADDRESS #define _DSPI3_ERR_IRQ _I2C2A_ERR_IRQ //_SPI4_ERR_IRQ #define _DSPI3_RX_IRQ _I2C2A_RX_IRQ //_SPI4_RX_IRQ #define _DSPI3_TX_IRQ _I2C2A_TX_IRQ //_SPI4_TX_IRQ #define _DSPI3_VECTOR _I2C_2_VECTOR //_SPI_4_VECTOR #define _DSPI3_IPL_ISR _I2C2_IPL_ISR //_SPI4_IPL_ISR #define _DSPI3_IPL _I2C2_IPL_IPC //_SPI4_IPL_IPC #define _DSPI3_SPL _I2C2_SPL_IPC //_SPI4_SPL_IPC

I am not sure whether or not DSPI3 I/O interrupt works this way, since I am just using DSPI0.

I have some questions about this.

  1. Can you explain me how to use interrupt driven I/O for DSPI.
  2. Could you tell me if my workaround have some problem.

Thank you for reading,


rasmadrak

Wed, 17 Oct 2012 08:41:33 +0000

Mhanuel - Ah, I didn't see that this was a previously posted bug ( I did search for it beforehand).

As for interrupt driven transfer you enable/disable interrupts and use a specific interrupt transfer DSPI call. So using transfer() does not use interrupts, unless I'm misinformed. :)

Gene - Thanks for your support and help! I'll just disable the interrupts until further notice. :)

Sorry for pointing out the bug... ;)


GeneApperson

Wed, 17 Oct 2012 20:06:24 +0000

Mhanuel

To use interrupt driven transfers with DSPI, you call the method enablIntTransfer to initialize for interrupt operation. Then you call the method intTransfer to begin a transfer. The transfer will occur in the background. You can call the method transCount to see if the transfer has completed. When transCount returns 0, all of the bytes have been transferred. You can call cancelTransfer to abort a transfer before it completes.

Your work around moves the conflicting interrupt service routines to other, non-conflicting, vectors. Doing it this way will also remove the conflict. Either removing the ISRs or changing them to different vectors will have the side effect of crashing the system if you try to do an interrupt driven transfer.

Using your method will also cause a conflict if you then try to use the peripherals whose vectors you have taken over (e.g. CAN1) and field interrupts for that peripheral. As long as you aren't trying to take interrupts from the other peripheral, though, there shouldn't be a problem.

rasmadrak,

You are correct, there are no interrupts involved when you use the transfer() method.

Sorry my code was causing problems. This is another of those constant reminders that I get of just how far short of perfect I am. :)

I'll get it fixed as soon as I can.

Gene


mhanuel

Thu, 18 Oct 2012 05:04:22 +0000

Gene,

Thank you for clarifying my doubts. (same for you rasmadrak).

Now I am more confident so that will not be a reason for my application to hang following your advice :roll:

Appreciated!