A board I'm currently working on has a primary interface over RS485 (it is expected to be part of a multi-drop network, with several like and different devices at the same time - with a single master controlling them). All of the communication works great, and the network design hasn't shown any issues yet, etc. The RS485 driver is an SN75176AD and its output goes to the RX/TX lines on the Atmega328P, which is running at 16Mhz w/ a crystal and 5V.
The board is designed to fit in as small of a space as possible (it's 1.5"x1.5") - it could be smaller, yes, but it has an A4983, Dual OK, and of course the SN75176 plus all the accoutrements, with pin-pads and such that's about as small as I've gotten it at this stage. Given this, I decided that adding a USB->serial converter was a luxury, but left the standard RX/TX lines accessible via pins.
The challenge I'm facing: RS-485 is the primary interface for the vast majority of users in its final destination. As such, for PC communication, a special USB->RS-485 adapter is required. I don't want the users to have one interface for interaction and yet another for programming the board, both because buying two USB adapter cables is an undesired expense on the user, and adding a USB port on the board will prevent it from being used in some of the cases which it is designed for (where the 1.5"x1.5" footprint is the absolute maximum that will fit).
After modifying optiboot 4.4 to check for uploads on power-up, and not just after external reset, I also changed it to eliminate interference from the RS485 driver on the RX line during upload using the standard RX/TX lines, by adding the following to the main function:
DDRD |= _BV(PORTD5);
PORTD |= _BV(PORTD5);
Digital 5 (PORTD5) is the control line which is shared between the DE/RE pins on the driver. Putting the driver in transmit mode (DE = RE = HIGH) causes it to release the RX line, which allows upload using the standard RX/TX lines (and another arduino salvaged for its FTDI interface =). So, at least this option works, ok.
Now, I'm working on the ability to upload via the RS485 interface, which requires the board to put the transceiver (ok, I've been calling it a driver, because it's a shorter word =) into the transmit state before transmitting data, and then putting it back into receive state to get more data. This is where I've run into a stumbling block, and I'm wondering if anyone else has tried something like this and can see what I've been missing as obvious - I hope!
So, to control the state of the driver, I made sure to change the above mod to the put the driver into receive mode first, and then modified putch() in the following way:
void putch(char ch) {
#ifndef SOFT_UART
while (!(UCSR0A & _BV(UDRE0)));
// enable transmit mode
PORTD |= _BV(PORTD5);
// clear out TXC0
UCSR0A |= _BV(TXC0);
UDR0 = ch;
// wait for transmit complete
while(!(UCSR0A & _BV(TXC0)) );
// enable receive mode
PORTD &= ~_BV(PORTD5);
I can validate that it somewhat works, as I see the first response byte go back to the RS485 cable (clear housing = I can see RX/TX leds on the adapter, RX = green TX = red) every time, but then it tends to get stuck here and we get the inevitable timeouts from avrdude.
An odd thing I encountered during testing was that if I disabled (via defines in the makefile) the LED flash functions, and then added a LED_PIN |= _BV(LED) to the beginning of the putch() function with no corresponding change to turn off the LED, it would light up for a fraction of second, no matter what the first watchdog timer is set to (went to _8S). Which, seems to indicate that it's bailing out quickly on a timeout? If I removed the first call to config the watchdog entirely, surprisingly about 5% of the time, I can get it to start uploading the sketch, only to lose sync at some random point. This, of course, only happens at 57,600 - any lower or higher baud rate, and it never starts uploading. Natch: to go to the lower bauds, like 9600, I had to add a special define to avoid the SOFT_UART, because the code included there triggers compiler errors.
Does anyone have any experience with this, that they could shed some light on why the oddity? Why would the first byte response be ignored? Or, is it possible that the driver is not ready when the first response from avrdude comes after the first byte sent by the bootloader?
Thanks!