Mighty-1284p core and SoftwareSerial/Pin Change Interrupts

There were problems with the way pin change interrupts were mapped for both the standard and the avr-developers variants. Because of the incorrect mapping, SoftwareSerial receive did not function for the Mighty* boards or for the avr-developers board, but the Bobuino board was OK so no changes there. There were also problems with the analog pin mapping for avr-developers.

Fixes have been pushed to GitHub, and I also changed the default branch to v1.0.6, but the v1.0.5 branch is still available.

Interesting, avr-developers variant has been shown wrong all this time, but I imagine no one much uses it anyways.

EDIT:
I just checked, and see what maniac did. In the pinout "diagrams", the original Sanguino had the Dx pins in straight order, and for some reason he re-ordered them in his "standard" variant. However, he incorrectly used the standard assignments rather than the Sanguino assignments in the actual code section, as shown below. The standard and Bobuino variants are correct, I think.

from maniac library:

// ATMEL ATMEGA644P / SANGUINO (also works for ATmega1284P)
//
//                   +---\/---+
//  INT0 (D 0) PB0  1|        |40  PA0 (AI 0 / D31)
//  INT1 (D 1) PB1  2|        |39  PA1 (AI 1 / D30)
//  INT2 (D 2) PB2  3|        |38  PA2 (AI 2 / D29)
//   PWM (D 3) PB3  4|        |37  PA3 (AI 3 / D28)
//   PWM (D 4) PB4  5|        |36  PA4 (AI 4 / D27)
//  MOSI (D 5) PB5  6|        |35  PA5 (AI 5 / D26)
//  MISO (D 6) PB6  7|        |34  PA6 (AI 6 / D25)
//   SCK (D 7) PB7  8|        |33  PA7 (AI 7 / D24)
//             RST  9|        |32  AREF
//             VCC 10|        |31  GND 
//             GND 11|        |30  AVCC
//           XTAL2 12|        |29  PC7 (D 23)
//           XTAL1 13|        |28  PC6 (D 22)
//  RX0 (D 8)  PD0 14|        |27  PC5 (D 21) TDI
//  TX0 (D 9)  PD1 15|        |26  PC4 (D 20) TDO
//  RX1 (D 10) PD2 16|        |25  PC3 (D 19) TMS
//  TX1 (D 11) PD3 17|        |24  PC2 (D 18) TCK
//  PWM (D 12) PD4 18|        |23  PC1 (D 17) SDA
//  PWM (D 13) PD5 19|        |22  PC0 (D 16) SCL
//  PWM (D 14) PD6 20|        |21  PD7 (D 15) PWM
//                   +--------+
//
....
static const uint8_t A0 = 24;
static const uint8_t A1 = 25;
static const uint8_t A2 = 26;
static const uint8_t A3 = 27;
static const uint8_t A4 = 28;
static const uint8_t A5 = 29;
static const uint8_t A6 = 30;
static const uint8_t A7 = 31;

Jack,

Thank you for your continuing support on the 1284p! I'll try to do this myself but I'm not too familiar with the timers:

Which PWM pin gets broken if you use the tone() function. Official arduino has it in the reference:

http://arduino.cc/en/Reference/Tone

I guess this is the revelent code in Tone.cpp

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

#define AVAILABLE_TONE_PINS 1
#define USE_TIMER2

const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ };

#elif defined(__AVR_ATmega8__)

#define AVAILABLE_TONE_PINS 1
#define USE_TIMER2

const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };

#elif defined(__AVR_ATmega32U4__)
 
#define AVAILABLE_TONE_PINS 1
#define USE_TIMER3
 
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 3 /*, 1 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
 
#else

#define AVAILABLE_TONE_PINS 1
#define USE_TIMER2

// Leave timer 0 to last.
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ };

#endif

So 1284p is the #else case that uses timer2, which breaks pwm of pins ???

According to 324/644/1284 spec sheet:

Peripheral Features
̶ Two 8-bit Timer/Counters with Separate Prescalers and Compare Modes
̶ One/two 16-bit Timer/Counter with Separate Prescaler, Compare Mode, and
Capture Mode

So this is from bobuino pins_arduino.h

const uint8_t PROGMEM digital_pin_to_timer_PGM[NUM_DIGITAL_PINS] =
{
  NOT_ON_TIMER, // D0 PD0
  NOT_ON_TIMER, // D1 PD1
  NOT_ON_TIMER, // D2 PD2
  NOT_ON_TIMER, // D3 PD3
  NOT_ON_TIMER, // D4 PB0
  NOT_ON_TIMER, // D5 PB1
  NOT_ON_TIMER, // D6 PB2
  TIMER0A, // D7 PB3
  TIMER1A, // D8 PD5
  TIMER2B, // D9 PD6
  TIMER0B, // D10 PB4
  NOT_ON_TIMER, // D11 PB5
  TIMER3A, // D12 PB6
  TIMER3B, // D13 PB7
  NOT_ON_TIMER, // D14 PA0
  NOT_ON_TIMER, // D15 PA1
  NOT_ON_TIMER, // D16 PA2
  NOT_ON_TIMER, // D17 PA3
  NOT_ON_TIMER, // D18 PA4
  NOT_ON_TIMER, // D19 PA5
  NOT_ON_TIMER, // D20 PA6
  NOT_ON_TIMER, // D21 PA7
  NOT_ON_TIMER, // D22 PC0
  NOT_ON_TIMER, // D23 PC1
  NOT_ON_TIMER, // D24 PC2
  NOT_ON_TIMER, // D25 PC3
  NOT_ON_TIMER, // D26 PC4
  NOT_ON_TIMER, // D27 PC5
  NOT_ON_TIMER, // D28 PC6
  NOT_ON_TIMER, // D29 PC7
  TIMER1B, // D30 PD4
  TIMER2A, // D31 PD7
};

So can I say that D9 and D31 PWM are broken if Tone is used, since they use timer2? Thanks.

Wow, that Tone.cpp code is the usual mess of "if..thens.. and buts..". And especially with all the commenting out. WTH?

In any case, for Bobuino, I'd say your selection of D9,D31 using Timer2 PWM is right. The Timer2 OCx signals are on pins 20 and 21 of the 1284 chip. As noted, Bob changed the pinout to better match the UNO header form-factor.

Jack, changing these macros affects the openGLCD library or any other library that is doing
direct port i/o using the macros to for their pin mappings.

I really wish the pin data table declarations were done differently so it could be shared by
libraries that need to do direct pin i/o. That way they would not have to duplicate this mapping data
but rather could use the same tables at compile time.
So far I've not been able to get anyone to makes changes on the way they declare
the mapping tables. The change is transparent to all existing code.

I use these analog pin to digital pin macros to detect which of the 4 variants of 1284 are in play.

  • standard
  • bobuino
  • Sleeping Beauty
  • avr developers/sanguino

if these mappings are wrong or are changed, it means my openGLCD code
incorrectly determines the variant and uses the wrong data tables or breaks with an error
at compile time.
If the declarations of the port mapping data tables were slightly changed,
they could be shared at compile time, and then libraries could do direct port i/o using
the compile time data without having to re-create the same data for compile time use.

On a side note, I'm seeing 3 different pin mappings of analog pins to digital pins for the Bobuino.
I'm sure some of this goes back to the confusion over analog pin# vs analog channel #.

I'm not sure which mapping is really correct or whether there was an actual change to the
mappings over time.
What is the correct mapping?

The older pins_arduino.h had the ascii chip pinout diagram mapping
analog pins 0-7 to analog pins 14 to 21 where analog 0 was digital pin 14
but the macro andlogInputToDigitalPin() mapped analog pins 0-7 to digital pins
21 to 14 where analog pin 0 was mapped to digital pin 21

In your current repo, there were 3 commits on Feb 11, 2012 after the first checkin
on Feb 10, 2012. They were all moving the analog to digital pin mappings around
and all of them have various issues of inconsistent and incorrect mappings between the diagram
and the macros or even between different macros.

There was a commit on may 5 2014, that made everything consistent
(diagram, macros, defines) for the analog to digital pin mappings in the pins_arduino.h
Unfortunately there is still an inconsistency between the pins_arduino.h
header file and the .ods file.
I don't quite understand that commit on may 5 2014 (perhaps it was branch merge?)
as I looks like pins_arduino.h was updated/correct but then that is when pins.ods shows up
in the tree but it shows up with an age much older than when then commit was done.

I did my macros based on the ascii diagram in the bobuino pins_arduino.h (as it was back in 2013)
and didn't closely look at the macros in bobuino/pins_arduino.h to notice the differences until today
so I didn't realize that the actual pin mappings didn't match the diagram back then.

Have a look at the bobuino .ods file in the git repo.
It is not in agreement with the current pins_arduino.h or any
of the analog to digital pin mappings I've seen, so I'm assuming it is is incorrect.
Regardless, it needs to be updated to match so we don't have an incorrect inconsistency.

So after looking at all this, I clearly need to update my openGLCD compile time detect
macros to properly detect which 1284 core is in play at compile time.
They depend on having an accurate analogInputToDigitalPin() macro.

What I don't know is what is the real mapping of Bobuino supposed to be?
It is great that it is all consistent in the pins_arduino.h header file but is this the real mapping?
And if so, it is different from what it was a few years ago and is everyone ok with the changes?

So what is the correct pin mappings of Bobuino?

--- bill

I did my macros based on the ascii diagram in the bobuino pins_arduino.h (as it was back in 2013)

The ADC pin mapping in the "original" maniac library for Bobuino was wrong, but we debugged it back in early 2013. maniac had left the bldg by then, never to be seen again, so his disto was never revamped.

Bob apparently has been distributing the fix with his Bobuino boards.

I assume jack has the correct fix in his distos.

oric_dan:
The ADC pin mapping in the "original" maniac library for Bobuino was wrong, but we debugged it back in early 2013. maniac had left the bldg by then, never to be seen again, so his disto was never revamped.

Bob apparently has been distributing the fix with his Bobuino boards.

I assume jack has the correct fix in his distos.

Well that doesn't match what happened in jacks 1284 repo.
As I outlined above, Jack made a mapping change to the pins_arduino.h file
in may of 2014 that changed how analog pins are mapped to digital pins.,
Also the .ods file does not match the pins_arduino file.

I guess will wait for jack's comments. Interestingly, I've been using the "original" fixes to the Bobuino variant mapping made in early 2013, in many many projects, and not had any problems at all.

For risk of making another statement, I believe the .ods file to be totally irrelevant.
http://forum.arduino.cc/index.php?topic=60001.msg1067695#msg1067695

I opened a pins.ods file and it opened up into an open office spreadsheet, so perhaps it's just an aid/tool he uses to build his various custom pins_arduino.h file?

Lefty

In any case, good luck on trying to keep this all straight, it's been a real trial. Eg,
http://forum.arduino.cc/index.php?topic=277769.0

While there are lots of moving parts it isn't that hard.
I strongly believe that when it comes to consistency of information, the same
information should not be duplicated in multiple places.
The pins.ods file if it is allowed to continue on in existence, should match the pins_arduino.h
but my preference would be to simple remove it from the tree to avoid any conflicts.

The bigger real problem is with the current way all these pins_arduino.h files are done
as is has so much duplicated mapping information in the file that must all be consistent
across the different defines and macros.

A much better way of handling it is the way the core pins are handled in Pauls teensy code.
In that implementation all the mappings of pins are defined up front and then through the use
of some clever cpp pasting macros, all the other macros
and data tables are absolutely identical across all variants with the only exception of the size/number
of pins for a variant.
It removes the possibility of all these accidental miss mappings like we have seen in the
various 1284 pins_arduino.h variant files.

The teensy core pins is much better way of handling things as it allows any entityto get a pin
mappings at either compile time or at run time (with the lookup tables).
Many years ago, the arduino team rejected handling the pins in this way.
Why was beyond me since it is 100% compatible with all the existing code but allows
new code to handle i/o better/faster when possible.

--- bill

There may be multiple copies, but I was under the impression there was the maniac original, but since he's MIA anymore, jack chose to provide an updated disto. Jack can certainly make his consistent if they're not so. As far getting Arduino-Centrale to change is probably hopeless from what I've seen. Eg, they still have the 2010 or so SD library in recent versions of the IDE even though Bill Greiman has been doing continual updates, he's had little success getting Centrale to incorporate them. So, someone like you with custom libraries is kind of caught in the middle.

I've stopped using SD library a few years ago and went directly for sdfat as recommended by Bill.
I don't see any mistakes in bobuino mapping. I agree, if the spreadsheet is not the direct source of the mapping i.e. generating code in the spreadsheet that is copied to pins_arduino.h, it should not be there. I do a lot of that, keeping spreadsheet with info and using excel code to generate c code and def.

AFAICT, the .ods file is not regular Ardunio stuff, and just something extraneous that was left in there by maniac.

oric_dan:
AFAICT, the .ods file is not regular Ardunio stuff, and just something extraneous that was left in there by maniac.

I didn't know who made it. It looks like maniac was doing what I described. String concats etc to build code from the spreadsheet info. So if anyone is still maintaining that and exporting the results to pins_arduino.h, it should be left there as a tool.

The pin mapping from DIP package is different from that of the QTFP so that portion can go or get some fancy update.

Hmmm, didn't mean to kick the hornet's nest quite so much :wink: (Seriously, I appreciate all the input.)

I almost deleted the .ods file in that last commit because I figured it was likely deprecated. I'll go ahead and do that next chance I get if no disagreement is heard.

To summarize, the recent changes for the standard variant consisted of changes to the pin change interrupt mapping macros only. Not sure how many libraries use those, SoftwareSerial is the only one I'm aware of, but my experience is admittedly limited. For the avr-developers variant, changes were made to the pin change interrupt macros as well as to the analog pin mapping macros. No changes of any sort were made to the Bobuino variant (so to answer the question which mappings are correct, I would say the macros currently in the pins_arduino.h file are correct.)

I haven't seen how the Teensy mappings are done, could well be a better approach. But either way, it seems that the tedious nature of getting all the mappings straight would remain. Even given the current approach, libraries that use the macros should count on them being correct, and raise issues if not. I certainly hope that libraries have not coded around existing issues. Bottom line, correcting these macros should not represent a liability to any library, quite the contrary, as shown by the example of SoftwareSerial.

As ever, if there are known problems, please just let me know, or better, raise an issue on the repo (as I'm pretty disillusioned with the state of the forum these days.)

@liudr, without actually testing it, I believe your analysis in reply #2 is correct (as therefore is @oric_dan's in reply #3), so I assume you're all set there.

Jack,

If I want to create another variant, do you recommend me to fork your one (don't know much about github myself), make my own, or add to yours?

My variant is derived from Bobuino and at the moment has no difference except for the name of the variant.

liudr:
Jack,

If I want to create another variant, do you recommend me to fork your one (don't know much about github myself), make my own, or add to yours?

My variant is derived from Bobuino and at the moment has no difference except for the name of the variant.

What's the point, then? A rose by any other name ;D Will it be different at some point? In what way?

I wouldn't call myself a GitHub guru either but basically the process would be to fork the repo, make changes to your local copy (I'd probably create a new branch first for my development purposes), then once complete, if the changes are likely to have general appeal, submit a pull request back to the repo.

Same reason arduino defined a bunch of digital pins and defs such as 0-13 and noInterrupts() instead of things like PA5, or CLI/STI. It's to make it beginner friendly.

Here is some details:

http://forum.arduino.cc/index.php?topic=299582.0

I also plan to make some virtual pins such as A20-A27 for external ADC channels 0-7 so programs can be easily written and modified with this device.

The teensy way of doing things does make things considerably less likely to have mapping inconstencies
within the variant files.
Currently there are multiple macros that do mappings but the way they are doing it now
they are holding independent mapping data and do not go back to a common set of defines.

For example look at the definition of A0
It is a #define to map it to a digital pin number.
However you can also get to the digital pin number using analogInputToDigitalPin(0)
The potential issue is that disagree since they don't go back to a common define to ensure they
never get out of sync.
And that is one of the issues that has happened with this core.
(the same pins are mapped differently with different macros)

In order to do raw port i/o that automatically maps correctly depending on the in play variant,
you have to be able to determine the pin mappings at compile time.
The way the Arduino data tables in the variant files that do digital pin mapping to port and
bit numbers is currently declared, does not allow the mappings to be determined at compile time.
This means that any code that wants to do raw port i/o has to duplicate the pin mappings
that are in the variant file.

The compile is smart enough to reach down into runtime data structure reference at compile time,
if the data is declared a particular way.

Complicating matters is that there can be more than a single pin mapping for a given processor type
which means the code has to determine the specific variant in play at compile time.
i.e. when 1284 is being compiled, I have to be able to tell which 1284 variant is being used
at compile time (avr_developers, bobuino, standard, or Sleeping Beauty) since they use
different pin mappings.
The way to determine this is to look at things that can be determined at compile time.
The openGLCD library uses analogInputToDigitalPin(0) and analogInputToDigitalPin(7)
Those two values are unique among the variants and can be used accurately determine
the variant.
So while I use the macros, I also have to know the expected result to be able to determine
this information at compile time.
So when things like the mappings are changed in the analogInputToDigitalPin() macro
(as they were on may 5, 2014) it breaks my code.

With the teensy way of doing things, all macros and data tables are derived from a single common
set of pin mapping defines. So while there are still multiple macros and data tables to access the
pin mappings, the actual mapping data itself is not duplicated.
Also the way the teensy defines work, it allows all mapping data to be accessed at compile time.

The current way the Arduino files are working, I have to have thousands of lines of complex macros
and compile time checks and conditionals to determine which variant is being used and
then duplicate the same pin mapping data.
Honestly, it sucks.
I would be great if the variant files were changed a bit to allow accessing the pin mapping
data at compile time.

There are couple of ways to go, I'd love to see paul's core pin macros used, which solves the
issues with digital pin mapping inconsistencies like we have seen in the 1284 variant files.

Then, if the declarations of the actual pin mapping data structures were declared slightly differently
code could literally reach down in the data table at compile time. This would solve having to duplicate
the pin mapping data for code that wants to do raw AVR port i/o.

In fact if this were done then the core digitalRead() digitalWrite() routines could be re done so
that if the arguments were all constants then the code would do raw port i/o and if not it could
fall back to the current way of doing pin mapping lookups.
(This is what teensy does and is why teensy i/o is so much faster than Uno, mega, Leonardo)

It requires no changes to the API nor to any sketch or library code. It would makes digital pin i/o
thousands of times faster in certain circumstances.
The Arduino team refused to adopt this but the 1284 core code could.
(assuming the 1284 core continues to exist as a separate core from the Team Arduino AVR core)
Then things like libraries that use things like shields which have known fixed pin numbers could benefit
from the much faster i/o.

--- bill

bperrybap:
The openGLCD library uses analogInputToDigitalPin(0) and analogInputToDigitalPin(7)
Those two values are unique among the variants and can be used accurately determine
the variant.

That seems like a less than desirable way to do it, and potentially trouble-prone. But since openGLCD works across different cores, maybe there wasn't much choice. At some point when a lot of the work was being done on the mighty-1284p refresh, someone (not me) did a fair amount of (good) work on the pins files and introduced a #define MIGHTY_1284P_VARIANT which seems useful.

But I'm not here to debate and I'm perfectly willing to have a look at the Teensy way of doing things. I'm not familiar at all with Teensy, I had a quick look through Paul S' repos, but not sure I'm looking at the right things, e.g. here or here. Would you be so kind as to provide a pointer to Paul's core pin macros?

One question I have, if the pin mapping method is changed in the mighty-1284p core, will that represent a transition that libraries have to make? Will two methods need to be maintained in parallel? Maybe the answer will be obvious once I look at things a little.

Bill, would I be correct in assuming that the recent changes did not in fact affect openGLCD? If they did, then please advise and we can either back them off or otherwise fix things up.

Actually, the MIGHTY_124P_VARIANT define is not useful for this kind of stuff.
because the way you would want to use would be in a #if expression like this:

#if (MIGHTY_124P_VARIANT == "BOBUINO")

However, it can't be used like this because
#if expressions cannot be used on strings
also, the preprocessor expands any macros
in the expression prior to evaluating the expression

So you end up with an expression of:

#if ("BOBUINO" == "BOBUINO")

which creates a cpp error because it is strings.

I'm guessing that whoever created it thought it was a good idea but never actually tried to use it.

Would you be so kind as to provide a pointer to Paul's core pin macros?

But lets talk offline about this rather than clutter up this thread.
(for the 1284 core, the mapping defines will be used at the top of the variant pins file
to create the sub macros and data tables in the lower portion of the pins file and
the lower portion will be identical in all the variants)
i.e.
CORE_BIT(0) will return the proper bit on ANY core for digital pin 0
CORE_PORTREG(0) will return the proper PORT register for digital pin 0
These concatenation macros are what does all the "magic" and could allow all the sub macros/defines/ and data tables to be identical in all the 1284 variant pin files, which eliminates the inconsistency errors.
It also allows any code that needs access to the pin mapping information at compile time to have it.
But lets move further discussion offline.

One question I have, if the pin mapping method is changed in the mighty-1284p core, will that represent a
transition that libraries have to make?

No. it is completely transparent. And that is what was so frustrating about the Team Arduino decision.

Will two methods need to be maintained in parallel?

No it is just a different way to create the defines.
There are base defines that define the mappings and then a couple of concatenation macros that are then used to create the existing macros/defines/data tables.

Bill, would I be correct in assuming that the recent changes did not in fact affect openGLCD? If they did, then please advise and we can either back them off or otherwise fix things up.

Yes.
I guess my comments were a bit confusing.
The recent changes caused me to look at the code in the repo and I noticed another commit
to the bobuino variant header file that was done since I did my code back in 2013 that broke my code.
This latest update did not affect the macro that I was using so it did not affect my code.
It was a previous update that broke my code.

But lets not go further with this discussion in this thread.
Lets move our discussion offline to work out the details of what can be done, if anything.
email me directly and we can discuss further.

--- bill