Author Topic: Strange behavior on ATmega 328  (Read 3485 times)

0 Members and 1 Guest are viewing this topic.

Paul

Strange behavior on ATmega 328
« on: November 14, 2011, 03:41:44 PM »
Hello,

I have a strange problem with a piece of code. I think it is a bug of some sort..
The hardware is a morse code keyer with a controller for an attenuator. The hardware which I use is very simple. An Atmel ATmega328P running at 8MHz on its internal oscillator. The keyer is connected to PD4. (It is a LED at the moment...) The serial port is going through a RS485 converter chip, with the TX enable (RX disable) connected to PD2.

The issue I am seeing is that the LED lights up very dimly if I use the code below. If I disconnect the LED I measure the full 5V voltage swing on the AVR pin, but for some reason the AVR is unable to deliver enough current.

The moment I move the statement on LINE 2 to the location of LINE 3, the LED starts lighting up properly...
If I move the LED from PD4 to PD3 the LED lights up properly with LINE 2 at the current position.

The only serial communication I see coming in, with the attenuator functions enabled, is the header which I send, and then after a period of time when the attenuator setting is changed to "20" the serial line becomes active again. This till the moment the attenuator is set at "40".
So this has clearly to do with bit PB2. The moment PB2 is HIGH, the serial port sends. So the only conclusion I can draw is that PB2 directly influences PD2.
This effect is there with LINE 2 at the current position and LINE 2 at the LINE 3 position.

The strange thing is if I remove all references to the attenuator, so basically remove LINE 1, 2 and 5, the keyer works fine with all serial comms. The only issue is then the dimly lit LED, unless I move it to PD3.

There is something going on with the PORTB and PORTD influencing each other in a strange way....

Can anyone tell me what I am doing wrong or what the issue might be? (And how to avoid it! :) )

See below for the code... (Sorry for the possibly lesser quality code...)

Thanks for all the help...

Paul
Quote

#include <TimedAction.h>

struct t_mtab { char c, pat; } ;

struct t_mtab morsetab[] = {
     {'.', 106}, {',', 115}, {':', 71}, {'\'', 94}, {'-', 97}, {'(', 45},
        {')', 109}, {'"', 82} , {'@', 86}, {'=', 49} , {'?', 76}, {'/', 41},
    {'A', 6}  , {'B', 17} , {'C', 21}, {'D', 9}  , {'E', 2} , {'F', 20},
   {'G', 11} , {'H', 16} , {'I', 4} , {'J', 30} , {'K', 13}, {'L', 18},
   {'M', 7}  , {'N', 5}  , {'O', 15}, {'P', 22} , {'Q', 27}, {'R', 10},
   {'S', 8}  , {'T', 3}  , {'U', 12}, {'V', 24} , {'W', 14}, {'X', 25},
   {'Y', 29} , {'Z', 19} , {'1', 62}, {'2', 60} , {'3', 56}, {'4', 48},
   {'5', 32} , {'6', 33} , {'7', 35}, {'8', 39} , {'9', 47}, {'0', 63}
} ;

#define N_MORSE  (sizeof(morsetab)/sizeof(morsetab[0]))

const int key1Pin = PD4;
const int att1Pin = PB5;
const int attPort = PORTB;
const int key1WPM = 12;

char key1Att;
char att1Set;
char* msg1 = "THE QUICK BROWN FOX JUMPES OVER THE LAZY DOG.";
int key1DotT = (int)(1200/key1WPM/5);

volatile char key1Busy;
volatile int key1Mark;
volatile int key1Space;
volatile char key1SpaceSent;
volatile char key1Pat;
volatile char* key1Msg;
volatile char key1MsgP;

TimedAction keyertimer = TimedAction (5, keyisr);

void setAttenuator (char att, char key) {
  att1Set = 20;
  if (att == 00) { portWrite(attPort, 146); return; }
  if (att == 10) { portWrite(attPort, 19); return; }
  if (att == 20) { portWrite(attPort, 134); return; }
  if (att == 30) { portWrite(attPort, 7); return; }
  if (att == 40) { portWrite(attPort, 152); return; }
  if (att == 50) { portWrite(attPort, 25); return; }
  if (att == 60) { portWrite(attPort, 140); return; }
  if (att == 70) { portWrite(attPort, 13); return; }
  portWrite(attPort, 146);
  return; 
}

void keyisr () {
  keyer1();
  setAtt();  // <-- LINE 1
}

void setAtt() {
  if (att1Set-- > 0) digitalWrite(att1Pin, HIGH); else digitalWrite(att1Pin, LOW);
}

void keyer1 () {
  unsigned char cnt;
  if (key1Busy == 1) {
    if (key1Mark > 0) { digitalWrite(key1Pin, HIGH); key1Mark--; return; }
    if (key1Space > 0) { digitalWrite(key1Pin, LOW); key1Space--; return; }
    if (key1Pat > 1) {
      if (key1Pat & 1) key1Mark = (3*key1DotT); else key1Mark = key1DotT;
      key1Space = (2*key1DotT);
      key1Pat = key1Pat / 2;
      return;
    }
    if (key1SpaceSent == 0) {
      key1Space = (3*key1DotT);
      key1SpaceSent = 1;
      return;
    }
    if (key1Msg[key1MsgP+1] != NULL) {
      key1MsgP++;
      if (key1Msg[key1MsgP] == ' ') {
        key1Space = (7*key1DotT);
        key1SpaceSent = 1;
        Serial.print(" ");
        return;
      }
      for (cnt=0; cnt<N_MORSE; cnt++) {
        if (morsetab[cnt].c == key1Msg[key1MsgP]) {
          key1Pat = morsetab[cnt].pat;
          Serial.print(key1Msg[key1MsgP]);
          key1SpaceSent = 0;
          return;
        }
      }
      key1Pat = 76;
    } else {
      key1MsgP = 0;
      key1Busy = 0;
    }
  }   
}

void setup() {
  portMode(attPort, OUTPUT); // <-- LINE 2
  pinMode(PD4, OUTPUT);
  pinMode(PD2, OUTPUT);
  pinMode(PC4, INPUT);
  pinMode(PC5, INPUT);
                              // <-- LINE 3
  digitalWrite(PD2, HIGH);    // <-- LINE 4

  Serial.begin(115200) ;
  Serial.println("Bug reproduction");
  Serial.println("================");
  delay(2500);
  key1Busy = 0;
  key1SpaceSent = 1;
  key1Att = 0;
  att1Set = 0;
  keyertimer.enable();
}

void loop() {
  keyertimer.check();
  if (key1Busy == 0) {
    Serial.println("");
    Serial.print("Attenuator setting: -");
    Serial.print(key1Att, DEC);
    Serial.println("dB");
    setAttenuator(key1Att, 1);    // <-- LINE 5
    key1Att = key1Att + 10;
    if (key1Att > 70) key1Att = 0;
    key1Msg = msg1;
    key1MsgP = -1;
    key1Busy = 1;
  }
}

bhagman

Re: Strange behavior on ATmega 328
« Reply #1 on: November 14, 2011, 10:53:58 PM »
I can see one glaring problem.

You're using constants such as "PD4" and "PB2" - but these will not work with any of the Wiring Framework functions.

Use these instead for the ATmega328P:

PD0 -> 0
PD1 -> 1
PD2 -> 2
PD3 -> 3
PD4 -> 4
PD5 -> 5
PD6 -> 6
PD7 -> 7

PB0 -> 8
PB1 -> 9
PB2 -> 10
PB3 -> 11
PB4 -> 12
PB5 -> 13

PC0 -> 14
PC1 -> 15
PC2 -> 16
PC3 -> 17
PC4 -> 18
PC5 -> 19

PORTD -> 0
PORTB -> 1
PORTC -> 2


So, for example:

Code: [Select]
const int key1Pin = 4;   // i.e. pin 4
const int att1Pin = 13;  // i.e. pin 13 = PB5
const int attPort = 1;   // i.e. port 1 = PORTB

Try that.

Paul

Re: Strange behavior on ATmega 328
« Reply #2 on: November 15, 2011, 06:26:27 AM »
Thanks for your reply.
But you write:
Quote
You're using constants such as "PD4" and "PB2" - but these will not work with any of the Wiring Framework functions.
How come the program works absolutely fine if I make the changes as described in my 1st post?

Where can I find the pin numbers in the documentation? I searched and could not find it; Therefore I tried the constants and it worked...?

I will change the program today and try again. I will let you know the outcome.

Paul
« Last Edit: November 15, 2011, 06:28:59 AM by Paul »

Paul

Re: Strange behavior on ATmega 328
« Reply #3 on: November 15, 2011, 07:20:06 PM »
It is working now :)
What I have done is all the pin names and port names defined using "#define PD0 0" etc.
Will that influence the functioning of the framework in any way? Is it advisable to do this or not? Would it be an option to include with the framework header files for each processor, so the pin names and port names could be used? Or is there a good reason not to do this???

I am still confused about the previous behavior though; Especially the dimly lit LED...  ???

Thanks

Paul


bhagman

Re: Strange behavior on ATmega 328
« Reply #4 on: November 16, 2011, 12:58:40 PM »
What I have done is all the pin names and port names defined using "#define PD0 0" etc.

I wouldn't recommend this.

It sounds to me that you have worked on Atmel's controllers before and that you're become accustomed to using the definitions provided by the header files defined within the AVR-GCC port of the GCC compiler.

The thing to remember with the Wiring Framework is that it abstracts away the fiddly bits of the controllers, so that it makes it easier for people to program them.

You will want to start using the pin numbering scheme used in the Wiring Framework to keep things consistent.  Adding new #defines will just confuse you later ("why did I redefine PD0?").


The reason why some of the things worked before was that you were just getting lucky by the fact that PD0 = pin 0, PD1 = pin 1, etc... (in the #ioxxxx.h files, PD0 = 0, PD1 = 1, etc) So things attached to PORTD were working as you expected.

Now, about the dimly lit LED - if the pin that it was on was not defined as an OUTPUT, it will stays defined as an INPUT, and on the AVR microcontrollers, when you write to a PORT, it turns on a weak pull-up which is what illuminated your LED (using very little current).

Paul

Re: Strange behavior on ATmega 328
« Reply #5 on: November 16, 2011, 02:03:30 PM »
Thanks for the explanation. Stupid of me that I did not think of the pullups...  :-[
What I am worried about is if I want to use/port the program to another controller that the pin numbers will be different. Looking at a part it is easy to see which pin names are available, but it would require cross referencing to see which pin corresponds to which wiring pin number.
Would it be an idea to include an overview / table within the documentation showing for each possible controller the pin number?

Thanks for your help...

Paul

cver65

Re: Strange behavior on ATmega 328
« Reply #6 on: March 29, 2012, 07:54:13 AM »
Hi Paul,

Actually, you could take the opposite point of view : if you switch boards, you still want digital pin "0" to be "0" and analog "0" to be "A0" as marked on the board. And not having to remember on which port/pin of the chip it is...

That's the very reason for the Wiring framework and similar IDE's to ask you which board you use ;-)

In addition, the framework also care for all the "fuse" settings and other parameters such as pre-dividers for timers etc. One of the very reason most people turn to IDEs like Wiring instead of starting with Eclipse and reinventing that wheel.