I am working with GNU AVR GCC version 5.4.0 and Atmelstudio 7.0.2397 and I have the following problem.
In the following Image, ye can see that up to line 13, the program has stored the address of function usart_send
into the transmitter
variable which is member of SimpleClass
object sc
.
The prototype of the transmitter
function is void (*transmitter)(uint8_t * txbuff, uint8_t len);
and usart_send
function prototype definition is void usart_send(uint8_t *, uint8_t);
.
Now when I step into the foo
function, notice that when inside the member function of the class's object, the address of transmitter
is now 0.
Similarly inside the function flush
, its value is still 0. So I cannot call the desired function. And this is what disassembly is showing and so is my MCU.
So I have the following code for SimpleClass.h
#pragma once
typedef unsigned char uint8_t;
#ifndef rxBufferLen
#define rxBufferLen 30
#endif
#ifndef txBufferLen
#define txBufferLen 30
#endif
class SimpleClass{
uint8_t rxbuffer[rxBufferLen]; ///< receiver buffer
uint8_t txBuffer[txBufferLen]; ///< transmitter buffer
uint8_t rxbuff_index, ///< rxbuffer index. Indicates where to put new data
txbuff_index; ///< txBuffer index. Indicates where to put new data
public:
void (*transmitter)(uint8_t * txbuff, uint8_t len);
void pushtx(uint8_t byte);
void pushrx(uint8_t byte);
void flush();
void foo();
};
Notice that have the length of txBuffer
and rxBuffer
defined using define
. And in incfile1.h
I have the following code.
#pragma once
#define rxBufferLen 50
#define txBufferLen 50
#include <avr/io.h>
#include "simpleClass.h"
#define TIMER0_CLOCK_PRESCALAR (3)
#define TIMER0_CLOCK_COUNT (0xff - 50)
void usart_init();
void timer0_init();
void serial_send_ln(const char *);
void usart_send(uint8_t *, uint8_t);
void usart_send_ln(uint32_t num);
In here I have redefined rxBufferLen
and txBufferLen
. This definition of define causes the above problem. If I remove these two lines, this code is working fine.
So you can see that by defining the buffer length for a buffer which is inside a class, causes its member function to loose the value the class's function pointer (which is a member variable). And I want to know why?
Here are many un used functions and this is because I was isolating bug(if it is a bug!) from my project.
main.cpp
#include "IncFile1.h"
SimpleClass sc;
int main(void)
{
usart_init();
timer0_init();
sc.transmitter = &usart_send;
sc.foo();
while (1)
{
}
}
IncFile.h
#pragma once
#define rxBufferLen 50
#define txBufferLen 50
#include <avr/io.h>
#include "simpleClass.h"
#define TIMER0_CLOCK_PRESCALAR (3)
#define TIMER0_CLOCK_COUNT (0xff - 50)
void usart_init();
void timer0_init();
void serial_send_ln(const char *);
void usart_send(uint8_t *, uint8_t);
void usart_send_ln(uint32_t num);
SimpleClass.h
#pragma once
typedef unsigned char uint8_t;
#ifndef rxBufferLen
#define rxBufferLen 30
#endif
#ifndef txBufferLen
#define txBufferLen 30
#endif
class SimpleClass{
uint8_t rxbuffer[rxBufferLen]; ///< receiver buffer
uint8_t txBuffer[txBufferLen]; ///< transmitter buffer
uint8_t rxbuff_index, ///< rxbuffer index. Indicates where to put new data
txbuff_index; ///< txBuffer index. Indicates where to put new data
public:
void (*transmitter)(uint8_t * txbuff, uint8_t len);
void pushtx(uint8_t byte);
void pushrx(uint8_t byte);
void flush();
void foo();
};
SimpleClass.cpp
#include "simpleClass.h"
void SimpleClass::flush(){
transmitter(txBuffer, txbuff_index);
}
void SimpleClass::pushtx(uint8_t byte){
txBuffer[txbuff_index++] = byte;
}
void SimpleClass::pushrx(uint8_t byte){
rxbuffer[rxbuff_index++] = byte;
}
void SimpleClass::foo(){
uint8_t dv = 0;
dv ++ ;
pushtx(0x01);
pushtx(0x02);
pushtx(0x03);
pushtx(0x04);
pushtx(0x05);
flush();
}
CPPFile1.cpp
#include "IncFile1.h"
void usart_init(){
unsigned int ubrr = 51;
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, stop bit */
UCSR0C = (3<<UCSZ00);
}
void timer0_init(){
TCCR0B = TIMER0_CLOCK_PRESCALAR;
TIMSK0 = 1; // enable timer overflow interrupt
TCNT0 = TIMER0_CLOCK_COUNT;
}
void serial_send(const char * c){
for(uint8_t i=0 ; c[i] != '\0';i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = c[i];
}
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = 0x0a;
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = 0x0d;
}
void usart_send(uint8_t *buff, uint8_t len){
for(uint8_t i = 0; i < len; i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = buff[i];
}
}
void usart_send_ln(uint32_t num){
for(uint8_t i =0;i < 4; i++){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = num >> (8*(3-i));
}
}
You are violating the One Definition Rule - linking C++ program where the same class is defined twice and these definitions are not identical is undefined behaviour. The compiler/linker is not required to check or report these errors.
You are doing just that:
CPPFile1.cpp
includes IncFile1.h
which creates SimpleClass
definition with buffers[50]
,SimpleClass.cpp
includes SimpleClass.h
with buffers[30]
.