I have been using Bluetooth module (HC-05) with Atmega8(both A and L) microcontroller to transmit data to my Android device. In following code an 8-bit signed(or unsigned doesn't made any change) value is sent over bluetooth to be displayed on device, this value starts at 0X00 and is incremented in every iteration:
#define F_CPU 1000000
#define BAUD 9600
#define MYUBRR (F_CPU/16/BAUD-1)
#include <avr/io.h>
#include <util/delay.h>
int main (void)
{
uint8_t data = 0;
UBRRH = (MYUBRR >> 8); // setting higher bits of UBRR
UBRRL = MYUBRR; // setting lower bit of UBRR
UCSRB = (1 << TXEN); // transmit enable
UCSRC = ((1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0)); //URSEL=USART reg selection (R/W), UCSZ1 & UCSZ0 set equal to 011 that is 8 bit data size
while (1)
{
UDR=data; // loading data in USART Data register (8-bit) and it will be transmitted immidiately
while(!(UCSRA&(1<<UDRE))); // waiting till complete data sent and UDRE flag set
_delay_ms(200); // after some time
data++; // incrementing data
}
return 0;
}
On the android device end there is "Bluetooth spp Pro" app to display the recieved data on screen.
Following is the configuration of recieve mode (Data is displayed as Hex values):
The data recieved here should start at 0X00 and go up to 0XFF instead it starts at 0X80 and increments upto 0XFF in a very unfamiliar manner.
Referring above image. The pattern I observed here is that the tens place digit starts at 8 and units place change from 0 to F then in next loop again it becomes 9 and unit place change from 0 to F after that instead of incrementing (expected) tens place again goes to 8 and then in next cycle it again becomes 9, after these four cycles of two repetetive words tens place increments to A and units place change from 0 to F and later the strange tens place pattern reappears for A and B then for C and D and later for E and F at tens place.
So my concern is:
Why is the device showing 80 for 00, as it is correctly working for ones place why is it not working for tens place as expected???
Thanks!!!
Edit:
This problem is neither Android version nor device manufacturer specific.
Problem was with voltage levels. Operating the microcontroller circuit on 3.2V and Bluetooth module on 3.8V solved the problem and data is transmitted as expected. However I am unable to predict an explanation for this.
Please help.
It is observed clearly on varying the potentiometer of voltage regulator, when I keep it below 3.20V data is transmitted smooth, and as the voltage level crosses 3.20V the tens place of data starts getting corrupted up to the point of complete data corruption and output becomes constant data 0XFE at 3.8V.
Related
I need to understand the code in "Real time clock" function rtc_interrupt. Code is
rtc_irq_data += 0x100;
rtc_irq_data &= ~0xff;
rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
I am unable to understand why it is += 0x100 and the rest of code.
From the Book "Linux kernel development", from Robert Love, that snippet of code has the following comment(s):
/*
* Can be an alarm interrupt, update complete interrupt,
* or a periodic interrupt. We store the status in the
* low byte and the number of interrupts received since
* the last read in the remainder of rtc_irq_data.
*/
As for rtc_irq_data += 0x100; So, we know there is a counter for the interrupts received in the high byte. Hence the 0x100. If a 16 bit hexadecimal number representation, where the highest byte is being added +1 (more one interrupt on the counter).
As for the second line, rtc_irq_data &= ~0xff; rtc_irq_data is being logically ANDED with the negation of 0xff, eg, with possibly 0xff00. The high part of the integer is being kept, and the low part being discarded. So supposing this was the first time being called, the value would now guaranteed to be 0x0100.
The last part rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); is doing a logical OR |= of the low byte (that is now 0 / 0x00) with as the RTC current status. Hence the comment "We store the status in the low byte".
As for doing a logical AND with 0xF0 in (CMOS_READ(RTC_INTR_FLAGS) & 0xF0) , consulting the original AT compatible RTC datasheet, INTR_FLAGS is REGISTER C, a register byte where only the 4 upwards bits are used. b7 = IRQF, b6 = FP, b5 = AF, b4 = UF,
b3 to b0
The unused bits of Status Register 1 are read as "0s". They cannot be
writen.
From RTC datasheet
Hence then as a good standard coding practice, making sure with the AND logical 0xF0 that the lower 4 bits are ignored.
I am trying to learn how to write a basic SPI driver and below is the probe function that I wrote.
What I am trying to do here is setup the spi device for fram(datasheet) and use the spi_sync_transfer()api description to get the manufacturer's id from the chip.
When I execute this code, I can see the data on the SPI bus using logic analyzer but I am unable to read it using the rx buffer. Am I missing something here? Could someone please help me with this?
static int fram_probe(struct spi_device *spi)
{
int err;
unsigned char ch16[] = {0x9F,0x00,0x00,0x00};// 0x9F => 10011111
unsigned char rx16[] = {0x00,0x00,0x00,0x00};
printk("[FRAM DRIVER] fram_probe called \n");
spi->max_speed_hz = 1000000;
spi->bits_per_word = 8;
spi->mode = (3);
err = spi_setup(spi);
if (err < 0) {
printk("[FRAM DRIVER::fram_probe spi_setup failed!\n");
return err;
}
printk("[FRAM DRIVER] spi_setup ok, cs: %d\n", spi->chip_select);
spi_element[0].tx_buf = ch16;
spi_element[1].rx_buf = rx16;
err = spi_sync_transfer(spi, spi_element, ARRAY_SIZE(spi_element)/2);
printk("rx16=%x %x %x %x\n",rx16[0],rx16[1],rx16[2],rx16[3]);
if (err < 0) {
printk("[FRAM DRIVER]::fram_probe spi_sync_transfer failed!\n");
return err;
}
return 0;
}
spi_element is not declared in this example. You should show that and also how all elements of that are array are filled. But just from the code that's there I see a couple mistakes.
You need to set the len parameter of spi_transfer. You've assigned the TX or RX buffer to ch16 or rx16 but not set the length of the buffer in either case.
You should zero out all the fields not used in the spi_transfer.
If you set the length to four, you would not be sending the proper command according to the datasheet. RDID expects a one byte command after which will follow four bytes of output data. You are writing a four byte command in your first transfer and then reading four bytes of data. The tx_buf in the first transfer should just be one byte.
And finally the number of transfers specified as the last argument to spi_sync_transfer() is incorrect. It should be 2 in this case because you have defined two, spi_element[0] and spi_element[1]. You could use ARRAY_SIZE() if spi_element was declared for the purpose of this message and you want to sent all transfers in the array.
Consider this as a way to better fill in the spi_transfers. It will take care of zeroing out fields that are not used, defines the transfers in a easy to see way, and changing the buffer sizes or the number of transfers is automatically accounted for in remaining code.
const char ch16[] = { 0x8f };
char rx16[4];
struct spi_transfer rdid[] = {
{ .tx_buf = ch16, .len = sizeof(ch16) },
{ .rx_buf = rx16, .len = sizeof(rx16) },
};
spi_transfer(spi, rdid, ARRAY_SIZE(rdid));
Since you have a scope, be sure to check that this operation happens under a single chip select pulse. I have found more than one Linux SPI driver to have a bug that pulses chip select when it should not. In some cases switching from TX to RX (like done above) will trigger a CS pulse. In other cases a CS pulse is generated for every word (8 bits here) of data.
Another thing you should change is use dev_info(&spi->dev, "device version %d", id)' and also dev_err() to print messages. This inserts the device name in a standard way instead of your hard-coded non-standard and inconsistent "[FRAME DRIVER]::" text. And sets the level of the message as appropriate.
Also, consider supporting device tree in your driver to read device properties. Then you can do things like change the SPI bus frequency for this device without rebuilding the kernel driver.
I want to read a byte sent by Bluetooth to the Atmega8 to process it. I found this function online to receive a byte
uint8_t receiveByte()
{
// Wait until a byte has been received
while((UCSRA&(1<<RXC)) == 0);
// Return received data
return UDR;
}
but it doesn't work by say turning a led on if 'a' was sent, so when I changed it and enabled port c to HIGH just before the while loop, and turned it low after it, but port c never gone low - which means this loop is infinite.
so my question is how to fix it or how can I read a byte from Bluetooth module
its atmega8-16pu and I configured it as follows:
/** define the cpu clock frequency*/
#define F_CPU 8000000UL
and fuse = 0xD9C4, from this site http://www.engbedded.com/fusecalc/
I am using a UART on a single board computer (Olimex A13) and I am trying to send and receive data through the UART. On the send side I have no problems. The Olimex board sends data to the serial buss and it is received on an external PC that is running putty terminal.
When I try to go in the other direction (PC sends data to be received by the Olimex board) I am running into a weird problem. When I start to send data, initially no data shows up on the Olimex board (I have tried 2 methods... cat /dev/ttyS0 and setting up a receive C program. Both exhibit the same results).
If I send data for a while (seems to vary from less than 10 characters to something over 20) at some point the uart seems to "wake up" and now data appears on the Olimex board. Once the data transfer starts it will keep going as long as I want and at fast or slow data rates. If I break out of the receive program or end the cat /dev/ttyS0 process and try to start receiving again, I need to go through the same process of "kicking" the uart until it decides it wants to receive again.
I have put an oscilloscope on the RX pin leading into the UART. The data coming in is at good levels and the data appears here from the very first send so the data is not being blocked initially and then arriving at the RX pin at some time later. So I am currently assuming that the issue is with a UART setting of some kind. Does anyone know of a UART setting that could possibly explain this behavior?
Below is the receive program that I am running. I don't think that there is an issue with it because I see the same behavior when I do a cat /dev/ttyS0. Any help here would be appreciated.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#define BAUDRATE B115200
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main()
{
int fd,c, res;
struct termios oldtio,newtio;
char buf[255];
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); return(-1); }
tcgetattr(fd,&oldtio); /* save current port settings */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
/* set input mode (non-canonical, no echo,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 5 chars received */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
while (STOP==FALSE) { /* loop for input */
res = read(fd,buf,255); /* returns after 5 chars have been input */
buf[res]=0; /* so we can printf... */
printf("String:%s - Character Count:%d\n", buf, res);
if (buf[0]=='z') STOP=TRUE;
}
tcsetattr(fd,TCSANOW,&oldtio);
}
Sawdust made these comments....
"sends data to the serial buss" -- RS232 is not a "buss". "When I
start to send data" -- Your writing style is confusing. What kind of
data is sent to the Olimex? For the cat /dev/ttyS0 test, how did you
set up the serial port, or was it in an unknown mode? bzero(&newtio,
sizeof(newtio)); -- That is a dangerous way to setup the termios
structure. newtio.c_cflag = BAUDRATE... That is not the proper way to
set the baud rate; you need to use the cfset[io]speed() functions. You
write of a "kick", yet you don't mention doing anything explicit
ok, RS232 is not a buss, I misspoke....
The data I am sending is a stream of characters that are typed on Putty terminal.
For the /dev/ttyS0 test the settings are the same as are set in the c program. I verified this using stty.
I copied this code from another post. I was not sure what bzero did. If you could expand on "dangerous" that would be great. Or better if you have a better way to do what bzero does?
I will update the way to set baud rate.. but send is working perfectly and I verified using stty that baudrate was indeed 115200.
As far as "kicking" I mean that I need to send a number of bytes of data to the uart before any appear on the console. Others have mentioned a FIFO that may be an issue here but the first characters that are sent are lost. For example if I were to send the string of characters abcdefg.... I could type up until k and then l would appear on the console, and then any future characters after l would also appear in the console. If I were to go through the same process again after starting the receive program (or cat /dev/ttyS0) the point where the receive starts appearing could be in a different place (i.e. at h or n).
We've been bashing our heads off of this one all morning. We've got some serial lines setup between an embedded linux device and an Ubuntu box. Our reads are getting screwed up because our code usually returns two (sometimes more, sometimes exactly one) message reads instead of one message read per actual message sent.
Here is the code that opens the serial port. InterCharTime is set to 4.
void COMClass::openPort()
{
struct termios tio;
this->fd = -1;
int tmpFD;
tempFD = open( port, O_RDWR | O_NOCTTY);
if (tempFD < 0)
{
cerr<< "the port is not opened"<< port <<"\n";
portOpen = 0;
return;
}
tio.c_cflag = BaudRate | CS8 | CLOCAL | CREAD ;
tio.c_oflag = 0;
tio.c_iflag = IGNPAR;
newtio.c_cc[VTIME] = InterCharTime;
newtio.c_cc[VMIN] = readBufferSize;
newtio.c_lflag = 0;
tcflush(tempFD, TCIFLUSH);
tcsetattr(tempFD,TCSANOW,&tio);
this->fd = tempFD;
portOpen = true;
}
The other end is configured similarly for communication, and has one small section of particular iterest:
while (1)
{
sprintf(out, "\r\nHello world %lu", ++ulCount);
puts(out);
WritePort((BYTE *)out, strlen(out)+1);
sleep(2);
} //while
Now, when I run a read thread on the receiving machine, "hello world" is usually broken up over a couple messages. Here is some sample output:
1: Hello
2: world 1
3: Hello
4: world 2
5: Hello
6: world 3
where number followed by a colon is one message recieved. Can you see any error we are making?
Thank you.
Edit:
For clarity, please view section 3.2 of the Linux Serial Programming HOWTO. To my understanding, with a VTIME of a couple seconds (meaning vtime is set anywhere between 10 and 50, trial-and-error), and a VMIN of 1, there should be no reason that the message is broken up over two separate messages.
I don't see why you are surprised.
You are asking for at least one byte. If your read() is asking for more, which seems probable since you are surprised you aren't getting the whole string in a single read, it can get whatever data is available up to the read() size. But all the data isn't available in a single read so your string is chopped up between reads.
In this scenario the timer doesn't really matter. The timer won't be set until at least one byte is available. But you have set the minimum at 1. So it just returns whatever number of bytes ( >= 1) are available up to read() size bytes.
If you are still experiencing this problem (realizing the question is old), and your code is accurate, you are setting your VTIME and VMIN in the newtio struct, and the rest of the other parameters in the tio struct.