Serial Support for Promicro changed and working

Post Reply
justk1w1
Posts: 62
Joined: Fri Jun 29, 2012 2:31 pm

Serial Support for Promicro changed and working

Post by justk1w1 »

Just completed making a few changes to the serial comms to get the MWConf to run over Serial xbee. I had a lot of trouble trying to get this running using the ATMEGA32U4 (leostick) and found that there were a number of changes that needed to be made to the low level serial to allow this to happen. I'm not sure if anyone had been running this over any of the other serial ports on the MEGA, but the changes should now support using any serial port. I haven't set it up and tested it on the MEGA yet, but wanted to submit it to a review and any comments.

I ended up splitting the serial sketch into two components:
1. Serial.ino - low level comms
2. Multiwii Serial communications protocol

The split seemed logical.

I also found that while the Serial Receive has been configured to use a buffer per UART the TX was not. It is also currently fixed so that it only uses port 0 (for the PROMICRO). I'm still looking at the code a bit more as the buffers are declared for all the UART's even if they are not selected to be used - probably not so important on the MEGA ( heaps of space) but on the ATMEGA32U4 space is a premium. The code could be further optimized, but my limited knowledge on the use of pointers in C sort of restricts that progress.

Also found that using the Serial UART (ring Buffer) code the buffer over runs and needs to be increased - the AUX information doesn't show in the MultiWiiConf unless the buffer is increased.

I guess the question now is what do I need to do to submit these changes?

User avatar
Hamburger
Posts: 2578
Joined: Tue Mar 01, 2011 2:14 pm
Location: air
Contact:

Re: Serial Support for Promicro changed and working

Post by Hamburger »

you could post a diff file here.

ronco
Posts: 317
Joined: Thu Aug 18, 2011 2:58 pm

Re: Serial Support for Promicro changed and working

Post by ronco »

Hi,

interesting :D .. so did you managed to split it to work with USB + serial 1 or just one of these?

i got a lot of requests to make a serial BT module working on the atmeg32u4.. but i think the best solution would be to be able to use both the USB for GUI and the serial 1 for BT xbee or whatever..

im not good in the new serial code .. so ill be happy if there is someone that can do it :D

feel free to post your serial code in here :)

btw. if you want a svn account you should pm alex

regards Felix

justk1w1
Posts: 62
Joined: Fri Jun 29, 2012 2:31 pm

Re: Serial Support for Promicro changed and working

Post by justk1w1 »

Felix,

Got it working for both Serial 1 and on the USB - was looking to try to make all the UART/USB actual channels that can be independently configured and used, but that's going to take a little more effort to merge the code for the Spectrum and GPS. This is the code that I split from the current Serial.ino

Code: Select all


#define PORT_NUM 1
#if defined(MEGA)
  #define UART_NUMBER 4
#else
  #if defined(LEOSTICK)
    #define UART_NUMBER 2
  #else
    #define UART_NUMBER 1
  #endif
#endif

#if defined(GPS_SERIAL)
  #define RX_BUFFER_SIZE 256 // 256 RX buffer is needed for GPS communication (64 or 128 was too short)
#else
  #define RX_BUFFER_SIZE 64
#endif
#define TX_BUFFER_SIZE 256
#define INBUF_SIZE 64

static volatile uint8_t serialHeadRX[UART_NUMBER],serialTailRX[UART_NUMBER];
static uint8_t serialBufferRX[RX_BUFFER_SIZE][UART_NUMBER];
static volatile uint8_t headTX[UART_NUMBER],tailTX[UART_NUMBER];
static uint8_t bufTX[TX_BUFFER_SIZE][UART_NUMBER];
static uint8_t inBuf[INBUF_SIZE][UART_NUMBER];

// *******************************************************
// For Teensy 2.0, these function emulate the API used for ProMicro
// it cant have the same name as in the arduino API because it wont compile for the promini (eaven if it will be not compiled)
// *******************************************************
#if defined(TEENSY20)
  unsigned char T_USB_Available(){
    int n = Serial.available();
    if (n > 255) n = 255;
    return n;
  }
#endif
//**********************************************
//
//Serial Open comm port and set speed
//
//*************************************************
void UartSendData(uint8_t portnum) {
  #if defined(PROMICRO) 
  // have to stop this from being defined if LEOSTICK and PORTNUM=1
  /*The USART Transmitter is enabled by setting the Transmit Enable (TXEN) bit in the UCSRnB
Register. When the Transmitter is enabled, the normal port operation of the TxDn pin is overridden
by the USART and given the function as the Transmitter’s serial output. The baud rate,
mode of operation and frame format must be set up once before doing any transmissions. If synchronous
operation is used, the clock on the XCKn pin will be overridden and used as
transmission clock.
*/   
if ( portnum==0 ){
      while(headTX[portnum] != tailTX[portnum]) {
          if (++tailTX[portnum] >= TX_BUFFER_SIZE) tailTX[portnum] = 0;
          uint8_t* p = bufTX[portnum]+tailTX[portnum];
     
        #if !defined(TEENSY20)
         USB_Send(USB_CDC_TX,p,1);  //used for output to the usb and not the uart1
        #else
         Serial.write(p,1);
        #endif
      }
}
      else
      {
        UCSR1B |= (1<<UDRIE1);
      }
  #else
     switch (portnum){
      case 0: UCSR0B |= (1<<UDRIE0);break; // enable transmitter UDRE interrupt if deactivacted
      case 1: UCSR1B |= (1<<UDRIE1);break; // enable transmitter UDRE interrupt if deactivacted
      case 2: UCSR2B |= (1<<UDRIE2);break; // enable transmitter UDRE interrupt if deactivacted
      case 3: UCSR3B |= (1<<UDRIE3);break; // enable transmitter UDRE interrupt if deactivacted
      }
  #endif
}

//**********************************************
//
//Serial Open comm port and set speed
//
//*************************************************
static void inline SerialOpen(uint8_t port, uint32_t baud) {
  /*The USART Receiver is enabled by writing the Receive Enable (RXENn) bit in the
UCSRnB Register to one. When the Receiver is enabled, the normal pin operation of the RxDn
pin is overridden by the USART and given the function as the Receiver’s serial input. The baud
rate, mode of operation and frame format must be set up once before any serial reception can
be done. If synchronous operation is used, the clock on the XCKn pin will be used as transfer
clock
*/
  uint8_t h = ((F_CPU  / 4 / baud -1) / 2) >> 8;
  uint8_t l = ((F_CPU  / 4 / baud -1) / 2);
  switch (port) {
    #if !defined(PROMICRO)
    case 0: UCSR0A  = (1<<U2X0); UBRR0H = h; UBRR0L = l; UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); break;
    #else
      #if (ARDUINO >= 100) && !defined(TEENSY20)
        case 0: UDIEN &= ~(1<<SOFE); break;// disable the USB frame interrupt of arduino (it causes strong jitter and we dont need it)
      #endif
    #endif
    #if defined(MEGA) || defined(PROMICRO)
    case 1: UCSR1A  = (1<<U2X1); UBRR1H = h; UBRR1L = l; UCSR1B |= (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1); break;
    #endif
    #if defined(MEGA)
    case 2: UCSR2A  = (1<<U2X2); UBRR2H = h; UBRR2L = l; UCSR2B |= (1<<RXEN2)|(1<<TXEN2)|(1<<RXCIE2); break;
    case 3: UCSR3A  = (1<<U2X3); UBRR3H = h; UBRR3L = l; UCSR3B |= (1<<RXEN3)|(1<<TXEN3)|(1<<RXCIE3); break;
    #endif
  }
}


//**********************************************
//
//Serial RX end comms routine
//
//*************************************************
static void inline SerialEnd(uint8_t port) {
  switch (port) {
    #if !defined(PROMICRO)
    case 0: UCSR0B &= ~((1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<UDRIE0)); break;
    #endif
    #if defined(MEGA) || defined(PROMICRO)
    case 1: UCSR1B &= ~((1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1)); break;
    #endif
    #if defined(MEGA)
    case 2: UCSR2B &= ~((1<<RXEN2)|(1<<TXEN2)|(1<<RXCIE2)); break;
    case 3: UCSR3B &= ~((1<<RXEN3)|(1<<TXEN3)|(1<<RXCIE3)); break;
    #endif
  }
}

//**********************************************
//
//Serial RX interrupt routine
//
//*************************************************
static void inline store_RXuart_in_buf(uint8_t data, uint8_t portnum) {
  uint8_t h = serialHeadRX[portnum];
  if (++h >= RX_BUFFER_SIZE) h = 0;
  if (h == serialTailRX[portnum]) return; // we did not bite our own tail?
  serialBufferRX[serialHeadRX[portnum]][portnum] = data;
  serialHeadRX[portnum] = h;
}

//**********************************************
//
//Serial RX interrupt definition
//
//*************************************************
#if (defined(MEGA) || defined(PROMICRO)) && !defined(SPEKTRUM)
  ISR(USART1_RX_vect) { store_RXuart_in_buf(UDR1, 1); }
#endif
#if defined(MEGA)
  ISR(USART0_RX_vect) { store_RXuart_in_buf(UDR0, 0); }
  ISR(USART2_RX_vect) { store_RXuart_in_buf(UDR2, 2); }
  ISR(USART3_RX_vect) { store_RXuart_in_buf(UDR3, 3); }
#endif


 //**********************************************
//
//TX Interrupt definition
//
//*************************************************
#if (defined(MEGA) || defined(PROMICRO)) && !defined(SPEKTRUM)
  ISR(USART1_UDRE_vect) { uint8_t t = tailTX[1];
    if (headTX[1] != t) {
      if (++t >= TX_BUFFER_SIZE) t = 0;
      UDR1 = bufTX[t][1];  // Transmit next byte in the ring
      tailTX[1] = t;
    }
    if (t == headTX[1]) UCSR1B &= ~(1<<UDRIE1); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
  }
#endif
#if defined(MEGA)
  ISR(USART0_UDRE_vect) { uint8_t t = tailTX[0];
    if (headTX[0] != t) {
      if (++t >= TX_BUFFER_SIZE) t = 0;
      UDR0 = bufTX[t][0];  // Transmit next byte in the ring
      tailTX[0] = t;
    }
    if (t == headTX[0]) UCSR0B &= ~(1<<UDRIE0); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
  }
  ISR(USART2_UDRE_vect) { uint8_t t = tailTX[2];
    if (headTX[2] != t) {
      if (++t >= TX_BUFFER_SIZE) t = 0;
      UDR2 = bufTX[t][2];  // Transmit next byte in the ring
      tailTX[2] = t;
    }
    if (t == headTX[2]) UCSR2B &= ~(1<<UDRIE2); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
  }
  ISR(USART3_UDRE_vect) { uint8_t t = tailTX[3];
    if (headTX[3] != t) {
      if (++t >= TX_BUFFER_SIZE) t = 0;
      UDR3 = bufTX[t][3];  // Transmit next byte in the ring
      tailTX[3] = t;
    }
    if (t == headTX) UCSR3B &= ~(1<<UDRIE3); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
  }
#endif


//**********************************************
//
//this is just used to read the information stored in the buffer
//
//*************************************************
uint8_t SerialRead(uint8_t port) {
  #if defined(PROMICRO) //&& defined(USB_SERIAL)
  // promicro should fall through to standard serial if port 1 defined
     #if defined(TEENSY20)
      if(port == 0) return Serial.read();
    #else
      #if (ARDUINO >= 100)
        if(port == 0) {USB_Flush(USB_CDC_TX);}
      #endif
      if(port == 0) return USB_Recv(USB_CDC_RX);     
    #endif
  #endif
 
  // this section will be executed for ATMEGA32u4 Serial1 defintion and all serial channels for MEGA
  uint8_t t = serialTailRX[port];
  uint8_t c = serialBufferRX[t][port];
  if (serialHeadRX[port] != t) {
    if (++t >= RX_BUFFER_SIZE) t = 0;
    serialTailRX[port] = t;
  }
  return c;
}
//**********************************************
//
//
//
//*************************************************
uint8_t SerialAvailable(uint8_t port) {
  #if defined(PROMICRO)
  // promicro should fall through to standard serial if port 1 defined
    #if !defined(TEENSY20)
      if(port == 0) return USB_Available(USB_CDC_RX);
    #else
      if(port == 0) return T_USB_Available();
    #endif
    //port = 0; // This removed to stop the force of port to 0
  #endif
  return (serialHeadRX[port] != serialTailRX[port]);
}
 
 
 //**********************************************
//
//  USART transmit function based on polling of the
// Data Register Empty (UDREn) Flag. When using frames with less than eight bits, the most significant
// bits written to the UDRn are ignored. The USART has to be initialized before the function
// can be used.
//
//*************************************************
 void SerialWrite(uint8_t port,uint8_t c){
 switch (port) {
    case 0: serialize8(c);UartSendData(0); break;                 // Serial0 TX is driven via a buffer and a background intterupt
    #if defined(MEGA) || defined(PROMICRO)
    case 1: while (!(UCSR1A & (1 << UDRE1))) ; UDR1 = c; break;  // Serial1 Serial2 and Serial3 TX are not driven via interrupts -- not sure about this
                                                                 // as previously we enabled the interrupts
    #endif
    #if defined(MEGA)
    case 2: while (!(UCSR2A & (1 << UDRE2))) ; UDR2 = c; break;
    case 3: while (!(UCSR3A & (1 << UDRE3))) ; UDR3 = c; break;
    #endif
  }
}
#endif


Also requires changes to the other code ( Serial_comm.ino) which is the MultiWii serial protocol
The code could be tidied up a little more, with the tx ISR's referencing a store_txUART_in_buffer(UDRx (as a pointer??),portnum) but I'm not that flash on C pointers. It needs to be tested on a MEGA though - which I will try to get to over the weekend.

Cheers

Alexinparis
Posts: 1630
Joined: Wed Jan 19, 2011 9:07 pm

Re: Serial Support for Promicro changed and working

Post by Alexinparis »

justk1w1 wrote:Also found that using the Serial UART (ring Buffer) code the buffer over runs and needs to be increased - the AUX information doesn't show in the MultiWiiConf unless the buffer is increased.

that's the reason why this part of code was inserted
in serialCom():

Code: Select all

if (bytesTXBuff > TX_BUFFER_SIZE - 40 ) return; // ensure there is enough free TX buffer to go further (40 bytes margin)

justk1w1
Posts: 62
Joined: Fri Jun 29, 2012 2:31 pm

Re: Serial Support for Promicro changed and working

Post by justk1w1 »

Thanks Alex,

Understand and agree with what you are saying - maybe I should have put that a little differently and said that "it appears that the buffer over runs". I had to decrease the buad rate for the xbee's to 38400 I found that unless I increased the TX buffer size then the AUX information didn't come through and did not display in the MultiWiiconf ( must be some sort of delay introduced with the xbees). All works fine using direct connect USB at 115200 - this was only an observation and I need to do a little more testing on it to see if the buffer size is the actual cause.
Cheers

ronco
Posts: 317
Joined: Thu Aug 18, 2011 2:58 pm

Re: Serial Support for Promicro changed and working

Post by ronco »

Hi,

i made a branch with a working serial 1 support that works with a ATmega32u4 but should also work with a mega.. so if active you can use both serial 0 (or USB) and serial 1.

thay also work togather at the same time .. but slower and there maybe some data getting lost :D ..

@alex
as im not that good in serial stuff .. maybe you would like to implement it :mrgreen: ?

it is located here http://code.google.com/p/multiwii/sourc ... rial_1_gui
and based on r1035.

i changed

- MultiWii.ino (just open serial 1 if the define is there)
- config.h (just added #define SERIAL1_COM_SPEED 115200)
- serial.ino (some more things ;) )

regards Felix

Neo360
Posts: 22
Joined: Sun Aug 12, 2012 1:49 pm

Re: Serial Support for Promicro changed and working

Post by Neo360 »

Now it's possible to use an Xbee Pro for telemetry?

Alexinparis
Posts: 1630
Joined: Wed Jan 19, 2011 9:07 pm

Re: Serial Support for Promicro changed and working

Post by Alexinparis »

Neo360 wrote:Now it's possible to use an Xbee Pro for telemetry?


yes absolutely

Neo360
Posts: 22
Joined: Sun Aug 12, 2012 1:49 pm

Re: Serial Support for Promicro changed and working

Post by Neo360 »

Alexinparis wrote:
Neo360 wrote:Now it's possible to use an Xbee Pro for telemetry?


yes absolutely


Nice. But sorry Alex i dont understand as i do!

Please you explain me the right metod?

P.s: i have the drotek flight ctrl with ATmega328p

Alexinparis
Posts: 1630
Joined: Wed Jan 19, 2011 9:07 pm

Re: Serial Support for Promicro changed and working

Post by Alexinparis »

Basically, xbee is just a way to transport an UART over the air.
It's like bluetooth, it relies on a RX and TX PIN.

I don't know how to setup the xbee modules for this purpose.

yeahiii
Posts: 5
Joined: Sun Dec 09, 2012 11:06 am

Re: Serial Support for Promicro changed and working

Post by yeahiii »

Has there been any progress on this topic? I'm currently about to implement telemetry (Graupner HoTT) using a second promicro. Using the second serial port (Serial1) would be great. Is the revision ronco commited to his branch stable enough to fly save?

Post Reply