I have to pass frequency and sampling channels to the atmega2560 via serial port, if I use echo from terminal to the serial it takes the arguments without problem, if I use dprintf the thing won't go on
I am using serial port USART0 in atmega2560
this is the code I run from pc
#include "serial_linux.h"
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
if (argc<6) {
printf("usage: %s <filename> <baudrate> <textfile> <number of channels> <frequency>", argv[0]);
return 0;
}
char* filename=argv[1];
int baudrate=atoi(argv[2]);
printf( "opening serial device [%s] ... ", filename);
int fd=serial_open(filename);
if (fd<=0) {
printf ("Error\n");
return 0;
} else {
printf ("Success\n");
}
printf( "setting baudrate [%d] ... ", baudrate);
int attribs=serial_set_interface_attribs(fd, baudrate, 0);
if (attribs) {
printf("Error\n");
return 0;
}
serial_set_blocking(fd, 1);
//we open text file where we write conversions
int fdoutput=open_file(argv[3]);
//////////////////////////////////////////////WORK IN PROGRESS
const int bsize=10;
char buf[bsize];
int n_read=read(fd, buf, bsize);
for (int i=0; i<n_read; ++i) {
printf("%c", buf[i]);
dprintf(fdoutput,"%c", buf[i]);
}
dprintf(fd ,"%s\n", argv[4]);
dprintf(fd ,"%s\n", argv[5]);
printf("%s",argv[4]);
printf("%s",argv[5]);
//////////////////////////////////////////////
while (1) {
int n_read=read(fd, buf, bsize);
for (int i=0; i<n_read; ++i) {
printf("%c", buf[i]);
dprintf(fdoutput,"%c", buf[i]);
}
}
}
this is what I run in atmega2560
#include <util/delay.h>
#include <stdio.h>
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "../avr_common/uart.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
uint8_t num_channels;//number of channels passed by client
uint8_t channels[8];
volatile uint8_t flag_config=0;
uint8_t i=0;
uint16_t ticks;
void setup_pwm(void) {
//configure 8 bit timer in fast PWM with Timer0
TCCR0A = (1 << COM0B1) | (1 << WGM01) | (1 << WGM00); // enable Fast PWM mode 3, mark first
TCCR0B = (1 << CS02) |(0 << CS01) | (1 << CS00); //set clock prescaler to 16MHz/128->9600
OCR0B = 100; //sets the desired pulse width (0-255)
DDRG |= (1 << PG5); // Set pin 4 (PG5) as output
}
void setup_adc(void) {
// enable adc, auto trigger, interrupt enable, start first rilevation, prescaler should be 2 or disabled? can't find out
ADCSRA = (( 1<<ADEN ) | ( 1<<ADATE ) | ( 1<<ADIE ) | (1 << ADSC) );
// Timer/Counter 1 Compare Match B
ADCSRB = (( 1<<ADTS2 ) | ( 1<<ADTS0 ));
// ref=AVcc + adc chan
ADMUX = (1 << REFS0) | (1 << ADLAR); //set Voltage reference to Avcc (5v), left adjust converted value, if this is commented we use AREF, last tree are for selecting A7 as input as shown in the table
}
void timer1_init ( uint16_t ticks )
{
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
TIMSK1 = 0;
TCCR1B = ( 1 << WGM12 ) ; // Configure for CTC mode 4 OCR1A=TOP
OCR1A = ticks; // Set CTC TOP value, if we set this to 32000 and prescaler to 1024 we have 16Mhz/1024=15600, 32000/15600=2 seconds interval between interrupts
// start timer, give it a clock
TCCR1B |= ( 1 << CS10 ); //(( 1 << CS10 ) | ( 1 << CS12 )) ; // Fcpu/1024, 64us tick @ 16 MHz
}
void set_ADMUX(void){
switch(channels[i]){
case 0:
ADMUX = (1 << REFS0) | (1 << ADLAR);
break;
case 1:
ADMUX = (1 << REFS0) | (1 << ADLAR) | (1 << MUX0);
break;
case 2:
ADMUX = (1 << REFS0) | (1 << ADLAR) | (1 << MUX1);
break;
case 3:
ADMUX = (1 << REFS0) | (1 << ADLAR) | (1 << MUX0) | (1 << MUX1);
break;
case 4:
ADMUX = (1 << REFS0) | (1 << ADLAR) | (1 << MUX2);
break;
case 5:
ADMUX = (1 << REFS0) | (1 << ADLAR) | (1 << MUX2) | (1 << MUX0);
break;
case 6:
ADMUX = (1 << REFS0) | (1 << ADLAR) | (1 << MUX2) | (1 << MUX1);
break;
case 7:
ADMUX = (1 << REFS0) | (1 << ADLAR) | (1 << MUX2) | (1 << MUX1) | (1 << MUX0);
break;
}
}
// ADC complete interrupt service routine
ISR(ADC_vect) {
// Wait for empty transmit buffer
while ( !(UCSR0A & (_BV(UDRE0))) ){;}
//Start transmission over usart0
printf("%d", ADCH);
while ( !(UCSR0A & (_BV(UDRE0))) ){;}
UDR0 = ' ';
i++;
if(i>num_channels-1){i=0;
//printf("\n");
while ( !(UCSR0A & (_BV(UDRE0))) ){;}
UDR0 = '\n';
}
set_ADMUX();
TIFR1 = ( 1<<OCF1B ); // clear Compare Match B Flag
}
/////////////////////////////////////////////////////////////////WORK IN PROGRESS
uint8_t ReceivedChar;
uint8_t buffer[255];
volatile int j=0;
// interrupt routine for receiving frequency and number of channels
ISR (USART0_RX_vect){
ReceivedChar=UDR0;
if(ReceivedChar=='\n'){
buffer[j]=ReceivedChar;
j=0;
//switch between cases in flag for configuration
switch(flag_config){
case 0:
flag_config=1;
break;
case 2:
flag_config=3;
break;
}
}
else{
//write on buffer the char we receive
buffer[j]=ReceivedChar;
j++;
}
}
//main function
int main(void){
_delay_ms(1000);
cli();
//initialize printf
printf_init();
//initialize pwm
setup_pwm();
sei();
printf("ready");
while(1){
if(flag_config==1){
//set frequency
ticks=16000000/atoi((const char *)buffer);
//set flag for configuration to second stage
flag_config=2;
}
if(flag_config==3){
cli();
num_channels=atoi((const char *)buffer);
//set the right amount of channels
for(int l=0; l<num_channels;l++){
channels[l]=l;
}
//initialize timer
timer1_init (ticks);
//initialize adc and start convertions
setup_adc();
//reset flag for configuration
flag_config=0;
sei();
}
}
}
If I run a terminal with the code on Linux side it will stop after in the WORK IN PROGRESS part and I have to open another terminal on which I run echo to send what should have been passed in that part, why do dprintf doesn't work?
EDIT: here's the functions opening and setting baudrate
#include "serial_linux.h"
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int serial_set_interface_attribs(int fd, int speed, int parity) {
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0) {
printf ("error %d from tcgetattr", errno);
return -1;
}
switch (speed){
case 19200:
speed=B19200;
break;
case 57600:
speed=B57600;
break;
case 115200:
speed=B115200;
break;
case 230400:
speed=B230400;
break;
case 576000:
speed=B576000;
break;
case 921600:
speed=B921600;
break;
default:
printf("cannot sed baudrate %d\n", speed);
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
cfmakeraw(&tty);
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
if (tcsetattr (fd, TCSANOW, &tty) != 0) {
printf ("error %d from tcsetattr", errno);
return -1;
}
return 0;
}
void serial_set_blocking(int fd, int should_block) {
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0) {
printf ("error %d from tggetattr", errno);
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
printf ("error %d setting term attributes", errno);
}
int serial_open(const char* name) {
int fd = open (name, O_RDWR | O_NOCTTY | O_SYNC );
if (fd < 0) {
printf ("error %d opening serial, fd %d\n", errno, fd);
}
return fd;
}
int open_file(const char* filename){
int res=open(filename, O_RDWR|O_CREAT, 0666);
if(res==-1){printf("error while opening textfile");}
return res;
}
I now notice it sometimes work when I run it on terminal, but not always, when it stops it looks like it stops just before the printf that should print "setting baudrate [%d] ... " in the pc code, so it is probably not a problem of the dprintf that comes later
Also the atmega code works fine when dealing with teraterm or cutecom, so it shouldn't be causing the problem
EDIT2: I added an fflush after the baudrate printf, and can now tell you that I need to run the code two times each time I want it to work, the first time it prints some row of sampled channels and then stops, the second time it works fine.