2
\$\begingroup\$

i recently bought an ESP-01 for a simple wi-fi project reading the temeprature from a website .

First i wired the ESP-01 directly on the TTL converter (cp2102) to read the temperature and everything worked just fine at 9600bps with the AT commands etc.

Then i created a program with winAVR for the mega32 to do the same thing using uart at 9600 bps (UBRRL = 0x68; ( or 104) for Fosc=16MHz) but it didn't work.

So i used a logic analyzer to check what went wrong with the characters i sent .

The result was very strange since some of the characters (of the AT commands sent) going from mega32 (Tx) to ESP-01 (Rx)are not transmitted correctly .

I tried to decrease the baudrate of the ESP-01 down to 4800 but the lowest baud is 9600. I don't know if some firmware version has the option for lower baudrate.

For some reason mega32 cannot accurately transmit all the characters and I cannot understand why this happens. Maybe it has something to do with crystal but when i changed it the same thing happened. I put some delay before the faulty characters which fixed a few but not all of them ( 1 or 2 out of 10+) (bad method, i know).

Also my i have connected my Tx pin (mega 32) to a voltage divider to convert it to 3.3v for the Rx pin of the ESP-01.

After lots of struggling i decided to ask for some help.

I attached my code and a snapshot from the logic analyzer for the AT command AT+CIPSTART=0,"TCP","api.thingspeak.com",80 (the corrupted one). The other two AT commands i use in the code before CIPSTART are transmitted almost... fine (the '\r' or '\n' are not transmitted correctly but somehow the ESP-01 accepts the commands).

The full code can be seen below

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "LCD4BIT.h"
#include <stdlib.h>
#include <stdio.h>

unsigned char interface_var = 0;
unsigned char counter[34];
unsigned char var = 0;

void usart_init(void)
{
    UCSRB |= (1<<TXEN) | (1<<RXEN) | (1<<RXCIE) ; //  enable receive transmit of usart
    UCSRC = (1<<UCSZ1) | (1<<UCSZ0) | (1<<URSEL);
    UBRRL = 0x68; //  baudrate = 9600 , Fosc=16MHz, UBRR value = 104 (0x68)
}
void usart_send( unsigned char ascii)
{
    while(!(UCSRA & (1<<UDRE)));
    UDR = ascii;

}
unsigned char usart_receive(void)
{
    while (!(UCSRA & (1<<RXC)));
    return UDR;
}
void send_AT( unsigned char message[])
{
    unsigned char i=0;
    while(message[i] != '\0')
{
    usart_send(message[i]);   // This sends data to esp-01
    i++;

}

int main(void)
{
    //OSCCAL = 0xA9;

    unsigned char AT[] = "AT\r\n";
    unsigned char CIPMUX[] = "AT+CIPMUX=1\r\n";
    unsigned char CIPSTART[] =  "AT+CIPSTART=0,\"TCP\",\"api.thingspeak.com\",80\r\n";
    unsigned char CIPSEND[] = "AT+CIPSEND=0,110\r\n";
    unsigned char GET_DATA[] = "GET https://api.thingspeak.com/apps/thinghttp/send_request?api_key=xxxxxxxxxxxxxxxx\r\n";
    unsigned char SEND_DATA[] = "GET https://api.thingspeak.com/update?api_key=xxxxxxxxxxxxxxxxxxxxxxx=50\r\n";

    //_delay_ms(200);
    LCD_init(); // intitialize LCD
    usart_init(); // initialize usart
    _delay_ms(500);
    sei();

    _delay_ms(200);
    send_AT(AT);

    _delay_ms(2000);
    send_AT(CIPMUX);   

    _delay_ms(2000);
    send_AT(CIPSTART);

    while(1)
    {   

    }//while(1) close

}// main close

ISR(USART_RXC_vect)    // Every time an AT command is sent correctly type OK on the LCD (Logic analyzer works better though :-p)
{

     unsigned char a = 0;
    //LCD_data(a);

    a = UDR;

    if(a == 'O')
    {LCD_data('O');}
    if(a == 'K')
    {LCD_data('K');}
    if(a == 'd')
    {LCD_data('d');}
    if(a == 'L')
    {LCD_data('L');}

}

mega32TxRxpins

breadboard connction

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Is there any reason you're not using the standard Serial class provided in the Arduino "runtime"? It doesn't look like you're doing anything special with the UART communication nor that you need to. On a side note, have you considered ditching the AT commands and just program the ESP directly, so it just communicates the temperature logged over serial (while doing all the "web scraping" by itself), relieving the Arduino from the need to deal with HTTP and AT commands parsing. Depending on your project, you could even ditch the Arduino completely and just use the ESP. \$\endgroup\$
    – Mishony
    May 7, 2016 at 21:17
  • \$\begingroup\$ Don't try to make it work all at once. Write a simple UART program (e.g. a loopback, or a program which prints all characters in a loop) and test it to perfection. \$\endgroup\$ May 9, 2016 at 11:27

3 Answers 3

5
\$\begingroup\$

Summary: Your symptoms fit with marginal UART bit timing errors. Use UBRRL = 0x67; instead of UBRRL = 0x68; for 9600 baud (really bits per second) UART from a 16MHz CPU clock, as recommended by Atmel.

Details: The fact that both your ESP8266 module and your logic analyser's own UART decoding, are failing to correctly decode some of your "9600 baud" ATmega32 UART output, is a clear indication that the ATmega32 is the likely source of the problem.

Then, the fact that there is sometimes a difference in interpretation between those two receivers (e.g. logic analyser doesn't decode '/r' or '/n' but the ESP8266 accepts the command and so it must have decoded one or both characters), shows that the problem is marginal.

For some reason mega32 cannot accurately transmit all the characters and I cannot understand why this happens.

You are correct, and well done for using a logic analyser. You would have found the problem yourself, if you used the analyser to get more precise timings of each bit - it is your bit rate (baud rate) which is slightly wrong, because you have used:

UBRRL = 0x68;

Actually, for an ATmega32 with 16MHz clock, the correct value is:

UBRRL = 0x67;

The slightly incorrect data rate is what affects different UART receivers differently (as you found yourself).

As I said, you just needed to progress a little further by checking the bit timings (an oscilloscope is typically used for this, but I expect your logic analyser can show the necessary bit timings too) and have the confidence that you were "on the right track" with your analysis of the observed results, and I'm sure you would have found the answer yourself :-)


Edited to add:

See the calculation here: Stack Overflow: What is the function of UBRRH and UBRRL registers in atmega32?

See the Atmel Application Note AVR306: Using the AVR USART on tinyAVR and megaAVR devices - Table 3-5 on page 7 shows that the correct UBRR value for 9600 baud with a 16MHz clock is 103 decimal = 0x67.

\$\endgroup\$
9
  • \$\begingroup\$ I changed the UBRRL to 67 and the transmission gets worse. More characters from the Tx pin of mega32 come out faulty.As a n additional note I have a 16MHz Crystal with 2 ceramic caps of 22pf each in parallel. \$\endgroup\$
    – Sparky
    May 8, 2016 at 9:25
  • \$\begingroup\$ @Lefteris - OK, we're making progress - though not as expected :-) As you see from the links I gave, UBRR=0x67 is the correct value. Your result of using that value suggests your crystal frequency is incorrect - already too low rather than too high. Since you say you've already tried 2 xtals, then I'm suspicious you're somehow altering the xtal frequency. Please (a) supply photos of that part of your ATmega32 PCB, and (b) use your logic analyser (or oscilloscope) to measure the actual bit period of the transmitted UART data - you can do this measurement without waiting for errors. \$\endgroup\$
    – SamGibson
    May 8, 2016 at 10:17
  • \$\begingroup\$ Ok. So i put UBRRL = 67, and after the transmission from the Tx pin of mega32 for character 'T' with bit stream of "0101 0100 the bit (pulse) width is 104.125 usec for High and 104.00 usec for LOW. So the period is 204.125 usec and the frequency is 4.80480 kHz. Since i use 9600 bps for the transmission the theoretical pulse( or bit) width is 104.167 usec for HIGH and LOW. and the frequency is 4.799 kHz which is a little lower. Now what? \$\endgroup\$
    – Sparky
    May 8, 2016 at 12:16
  • \$\begingroup\$ @Lefteris - (a) Still waiting for the photos :-) (b) I'm surprised that the high & low bit times are different. More measurements needed to confirm whether that is always the case. You might find that using "U" characters (equal numbers of high & low bits) make it easier for you. Perhaps your clock is not running at the wrong speed, but is unstable? (c) Is 0.125us the best resolution of your logic analyser - in other words, is it possible that the real bit width is somewhere between 104.125us and 104.0us but the analyser can only chose one of those two numbers? (d) Perhaps take this to chat? \$\endgroup\$
    – SamGibson
    May 8, 2016 at 13:16
  • \$\begingroup\$ a) i tried to take some photos but the phone doesn't focus enough (blurry) for close shots b)Yes i measured the 'U' Character and the widths are slightly different for 1 and 0 meaning that pulse width for HIGH is 104.250 usec and LOW is --103.875 OR 104.00 usec--. I know.. something is going on here but i don't know what. Is there any chance that i need more than 22pF ceramic capacitors for example 27pf or 18 pf?? \$\endgroup\$
    – Sparky
    May 8, 2016 at 13:51
3
\$\begingroup\$

Problem Solved! There were two things i was doing wrong.

First of all i used UBRRL = 0x68 which was wrong. It must be UBRRL = 0x67; Check Sam Gibson's answer above ( the links too).

And second since i had to use a voltage level converter from 5v to 3.3v i used a voltage divider from the Tx pin of the mega32 to the Rx pin of the esp-01 (since it is 3.3v tolerant). But the voltage divider resistor values i used were too large (10k and 20k). So according to gbulmer's suggestion above i changed the resistors to 2k and 4k. And it worked. Since the voltage divider gives the same voltage level with both sets of resistors the only thing that changes is the current passing to the Rx pin of the ESP-01. It must have something to do with the Rx's input capacitance of the ESP8266.

But the important thing for me here ,which i would like to share with you, is the debugging procedure and not the result as a result since this will help you find the problem faster and with less frustration not only for this project but for any project involving Serial Communication.

So the procedure i used is the following one

  1. Connect the ESP-01 directly to the USB-to-TTL module (I use CP2102)
  2. Connect it to your PC and open a terminal application (I use "Terminal")
  3. Double check UART settings of the Terminal to match with the settings of ESP (baudrate, stopbits, etc.)
  4. Check both CR=CR+LF and +CR (at the bottom)
  5. Send the AT commands you want to the ESP and wait for a reply from ESP

If everything has been correctly set the ESP must respond accordingly. Which is GOOD! Don't go further until this works.

  1. Create a simple C program like the one above with the same AT commands you used in Terminal.
  2. Be very careful with the escape characters such as '\r' '\n' '\"' (check wiki-pedia) inside your strings otherwise the ESP will respond with an error.
  3. Connect your oscilloscope or Logic analyzer to the Tx Pin of the micro-controller. (I prefer Logic analyzer since it shows you the actual characters transmitted).
  4. If the Logic Analyzer shows corrupted character transmission...

9a. Check the UBRRL value of the uC and try again.(For 9600 baudrate the UBRRL = 0x67 but sometimes UBRRL = 0x68 works without errors too...) 9b. Put small voltage divider resistors for the Tx pin of the uC (1k and 2k would be fine) and try again. (Large values like 10k and 20k will corrupt your transmission for sure) 9c. Check the power supply of both ESP and microcontroller and try again. (Fluctuations of the Supply voltages (5v for uC and 3.3v for ESP) can corrupt the transmission)

  1. If the transmission is is still corrupted disconnect the ESP Rx and Tx from the micro controller Tx and Rx pins.
  2. Connect the Tx and Rx pins of micro-controller to the USB-to-TTL module and connect to the computer
  3. At the same time connect the Logic analyzer to the Tx and Rx of the micro-controller.
  4. Initiate a transmission with the micro-controller and in the receive tab of Terminal you will see the incoming data from the micro-controller.
  5. Check if the received data/commands are the same with those you typed in your C code.
  6. If the received commands are corrupted check your code, your UART settings of both microcontroller and Terminal an try again.
  7. Also check the received characters with your Logic analyzer. It helps a lot

I believe that the procedure above will help you understand what went wrong with your ESP-01 transmissions (if any).

It hope this post to be helpful.

\$\endgroup\$
1
\$\begingroup\$

There are a bunch of possible causes.

Are you certain the data format and rate is compatible?

Are both mega and ESP8266 using the same data (bits) size, parity and stop bits? e.g. 8 data bits, no parity, 1 stop bit (or whatever). Being different would cause a problem which might be effected by printing extra characters.

Have you tried writing a simple program to send data from one, and have the other send it back, which tries all possible character codes? Start with printable characters, eg.

int buff[256];
int i = 0;
for (char c=' '; c<127; c++) {
  Serial.print(c);
  if (Serial.available()) {
     char inc = Serial.read();
     buff[inc] = i;
     i++;
   }
}
while (Serial.available()) {
   char inc = Serial.read();
   buff[inc] = i;
   i++;
}

WARNING - I haven't compiled or tested this code

All character codes should get through. If that is okay, then do the same with print(0x80|c); to try high-bit-set printable characters, then all codes which will include control codes like \r and \n. The idea is to detect codes which get corrupted or 'swallowed', and discover a pattern.

Edit:
You might exclude some possibilities by looping data straight back into the mega or running a similar program on the ESP8266. This almost must work, but if it doesn't it changes the places to look.

\$\endgroup\$
2
  • \$\begingroup\$ No i haven't tried that. I will try it and post the results. One more thing i want to mention is that i have connected the Tx pin of atmega32 (5v) to a voltage divider 10k and 20k to produce 3.3v for the Rx pin of the ESP8266. Is there any chance that the corrupted characters are a result of this? \$\endgroup\$
    – Sparky
    May 7, 2016 at 20:50
  • 2
    \$\begingroup\$ 10k/20k is bigger than I'd use. I'd try to find the ESP8266 spec (which I've not read), but I'd use 1k/2k. \$\endgroup\$
    – gbulmer
    May 7, 2016 at 21:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.