problems with softserial and ATtiny85

hi all,

i am using an ATtiny to receive serial commands and respond to them by transmitting infrared commands.

what i would like to do is simulate the original remote, and one of the features of the remote is to have extra commands if the button is held down.

i made a mock up with a regular arduino and loading up hyper terminal on the computer. when i hold down a key on the computer it triggers the arduino and the device responds as if a remote with the button held down has been pointed at it. in other words it works fine

but then i ported the code to an ATtiny85 using an external 16mhz resonator (the same as the ones on the arduino pro mini) and of course i had to use Softserial but now the hold feature doesn't work

sending one serial command works perfectly, but sending serial commands repeatedly doesn't work like it did on the regular arduino

i hope all that makes sense, its a bit difficult to explain but one thing i would like to know is the possible limits of softserial compared to hardware serial

thanks guys!

"Hi guys. I have a code problem, but I'm not going to show you any code. Please help".

Did I paraphrase that correctly?

why do people on this forum have to be so passive aggressive?

no matter how much code i post it wont answer my question: "what are the limits of software serial compared to hardware serial?"

but seeing as people don't read unless it is in a little code window, here:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(0, 1); // RX, TX


#define TOPBIT 0x80000000

#define NEC_HDR_MARK	9000
#define NEC_HDR_SPACE	4500
#define NEC_BIT_MARK	560
#define NEC_ONE_SPACE	1600
#define NEC_ZERO_SPACE	560
#define NEC_RPT_SPACE	2250

int inByte = 0;

void setup()
{
  DDRB  = DDRB  &~B00000100;
  PORTB = PORTB &~B00000100;
  mySerial.begin(9600);
}

void loop()
{
  while (mySerial.available() > 1) {  //removes lag, serial fills up and continues to repeat scommands even after serial input has stopped
    mySerial.read(); 
  }
  if (mySerial.available() > 0) {
    inByte = mySerial.read();
      switch (inByte) {
      case 99:  //c
        um_sendNEC(0xB54A9867, 32);  //Wheel Clockwise
        um_sendNEC(0xF50AFE01, 32);  //Wheel Clockwise
      break;
      case 97:  //a
        um_sendNEC(0xB54A9867, 32);  //Wheel Anticlockwise
        um_sendNEC(0xF50A7E81, 32);  //Wheel Anticlockwise
      break;
      case 98:  //b
        um_sendNEC(0xB54A9867, 32);  //Centre Button
        um_sendNEC(0xF50ABE41, 32);  //Centre Button
      break;
      case 43:  //+
        um_sendNEC(0xB54A50AF, 32);  //Vol Up
      break;
      case 45:  //-
        um_sendNEC(0xB54AD02F, 32);  //Vol Down
      break;
      case 114: //r
        um_sendNEC(0xB54A48B7, 32);  //BAND
      break;
      case 116: //t
        um_sendNEC(0xB54A30CF, 32);  //ATT
      break;
      case 100: //d
        um_sendNEC(0xB54A9867, 32);  //DISP
        um_sendNEC(0xF50AB649, 32);  //DISP
      break;
      case 115: //s
        um_sendNEC(0xB54A58A7, 32);  //SRC
      break;
      case 101: //e
        um_sendNEC(0xB54AD22D, 32);  //EQ
      break;
      case 102: //f
        um_sendNEC(0xB54A9867, 32);  //DF
        um_sendNEC(0xF50A16E9, 32);  //DF
      break;
      case 117: //u
        um_sendNEC(0xB54A02FD, 32);  //Up
      break;
      case 111: //o
        um_sendNEC(0xB54A827D, 32);  //Down
      break;
      case 108: //l
        um_sendNEC(0xB54A42BD, 32);  //Left
      break;
      case 105: //i
        um_sendNEC(0xB54AC23D, 32);  //Right
      break;
      default:
        inByte = 0;
    }
   // mySerial.write(inByte);
    inByte = 0;
  }
}

void um_sendNEC(unsigned long data, int nbits)
{
  um_mark(NEC_HDR_MARK);
  um_space(NEC_HDR_SPACE);
  for (int i = 0; i < nbits; i++) {
    if (data & TOPBIT) {
      um_mark(NEC_BIT_MARK);
      um_space(NEC_ONE_SPACE);
    }
    else {
      um_mark(NEC_BIT_MARK);
      um_space(NEC_ZERO_SPACE);
    }
    data <<= 1;
  }
  um_mark(NEC_BIT_MARK);
  um_space(0);
}


void um_mark(int time) {
  DDRB  = DDRB  | B00000100;
  delayMicroseconds(time);
}

void um_space(int time) {
  DDRB  = DDRB  &~B00000100;
  delayMicroseconds(time);
}

why do people on this forum have to be so passive aggressive?

Who's being passive?

  while (mySerial.available() > 1) {  //removes lag, serial fills up and continues to repeat scommands even after serial input has stopped
    mySerial.read(); 
  }

Why? If there is more than one byte in the buffer, throw away all the data except the last byte. Perhaps the data that you want just hit the bit bucket.

      case 99:  //c

Wouldn't

      case 'c':

be easier to understand and modify (and maintain)?

what are the limits of software serial compared to hardware serial?

Software serial's interrupts can interfere with other things on the Arduino (or ATTiny). HardwareSerial's interrupts are processed much faster, so the possibility of interference is less.

thank you for the reply,

the while loop removes excess data so that only current data is being processed, if no more data is received then i don't want it to continue processing data in the buffer. but i have tried the code without this loop and still doesn't work, and this loop does work on the ATmega328 version, so i know the loop is not to blame.

thanks for the recommendation i will change my case statements to ASCII

can you be a bit more specific about what conflicts with software serial? as i said before, the atmega version works fine with hardware serial so i am assuming that the problem lies with the software serial.

Can I suggest you try the tiny core I wrote?

It has software serial routines which are designed to mimic the way the hardware serial library does, which means you dont need the softwareserial library, simply use the normal Serial.print(), Serial.available(), Serial.read() commands etc. as you would for a regular arduino. There are no set baud rates, and I have had success with rates as high as 115200.

There are two small caveats/differences between it and Hardware serial.
The first is that TX must be digital 0 and RX must be digital 1 (which is just swapping RX and TX in your case). This i because my library uses the built in analog comparator to supply an interrupt vector. It features the same ring buffer as Hardware Serial does meaning that polling is not required.
The second is that is cannot transmit and recieve Serial data at the same time (its Half Duplex), but you don't appear to need to.

thanks very much for that Tom,

I tried the new core but unfortunately the results were still the same, it seems like what ever difference there is between hardware and software serial, is the difference between this working and not working.

the only thing i can think is happening is that the ATtiny is picking up a serial byte right in the middle, this would then be rejected by the switch case as not a valid input and for a fraction of a second the ATtiny would stop transmitting IR, and the receiver might interpret that as a button debounce on the remote control.

it works fine if i have separate commands that drive the hold functions, and basically loop round and retransmit the IR signal about 16 times, but thats not really what i was hoping for. my original idea was going to use an ATmega382 but it seemed like such a waste for such a simple job, but the lack of hardware serial on the ATtiny85 makes it very difficult to do what i want to do.

NeX:
i am using an ATtiny to receive serial commands...

Sent from what?

To prove it's a software serial problem and not an ATtiny one could you try it on your 328 using software serial instead of hardware serial. Maybe jumper the hardware RX/TX pins to a couple of normal pins that software serial reads/writes. Maybe it's something simple like you need to pull down the RX pin on your hardware.

NeX:
but then i ported the code to an ATtiny85 using an external 16 MHz resonator...

Are you certain the processor is running from the resonator and not the internal oscillator?

the serial is being sent from a computer, at the moment it is from Hyper terminal but in the future it will be a custom application.

also in the final version this will be driven with RS232, where as at the moment i am using the FTDI chip from the arduino board.

i am not sure how i would try software serial on a 328? the board has the FTDI chip hard wired to TX and RX, at the moment i am using the board with the chip removed just as a serial converter to drive the ATtiny. if i use the original 328, won't the hard wired tx and rx pins automatically interrupt the processor even if i jump those pins over to a software serial port?

i am sure the ATtiny is using the external resonator because it doesn't respond if i disconnect it, but it may be that the resonator is not accurate enough, maybe it needs a real crystal...

thanks for the replies everyone

just as a note, i think i have worked out a fix to solve my problem. instead of asking the ATtiny to transmit on receiving serial and expect it to transmit at regular enough intervals, i am going to get it to transmit on receiving a single serial command and repeat that command until it receives a stop command. it might not work because if the ATtiny misses that stop command it could be transmitting for ever. i can put a limit in to maybe stop after 16 transmissions, but still it may not work

i am not sure how i would try software serial on a 328? the board has the FTDI chip hard wired to TX and RX, at the moment i am using the board with the chip removed just as a serial converter to drive the ATtiny. if i use the original 328, won't the hard wired tx and rx pins automatically interrupt the processor even if i jump those pins over to a software serial port?

I did not realize you was using the arduino board. That seems to rule out hardware problem unless the patch cables to the ATtiny are long/noisy.
I'm not sure about the core of arduino but I would expect the hardware UART pins only gets configured and used if you do a Serial.begin otherwise the pins should behave just like any other pins.

hmmm, if the patch cables to the ATtiny where to long, (including the one to the resonator) could that have an effect?

at the moment i have ribbon cable soldered directly to an SMD 85, the ribbon cable is maybe 8cm long. at the other end they are attached to the arduino board, and two of the wires are stripped back and attached to the SMD resonator.

could it be that the resonator is too far from the chip? it has internal capacitors btw

NeX:
hmmm, if the patch cables to the ATtiny where to long, (including the one to the resonator) could that have an effect?

at the moment i have ribbon cable soldered directly to an SMD 85, the ribbon cable is maybe 8cm long. at the other end they are attached to the arduino board, and two of the wires are stripped back and attached to the SMD resonator.

A long lead like this will effect the resonator signal but not sure if this would be the cause. Can you program the ATtiny to use the internal 8Mhz clock instead if the Serial rate is not to high.

it was my understanding that the internal resonator is too unpredictable to function with serial, but i have moved the crystal so it is now within a few millimeters of the ATtiny and there is no change.

i have however found a possible work around, but it is not responding perfectly.

can someone take a look at this code and maybe see if there is a better way of doing it? the code also doesn't allow for different serial commands, only to exit the existing one, which is no good.

      case 's':
        while (!stopByte) {
          um_sendNEC(0xB54A58A7, 32);  //SRC
          IRcount ++;
          if (Serial.available() > 0) {
           if (Serial.read() == 'x') stopByte = true;
          }
          if (IRcount >= 16) stopByte = true;
        }
        IRcount = 0;
        stopByte = false;
      break;