unable to split/modularize my project

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

here is my main file

/*
 * nec decoder.c
 *
 * Created: 11-05-2020 20:13:54
 * Author : jeet
 */ 

#define F_CPU 16000000UL

#include <avr/io.h>
#include <stdio.h>
#include <stdbool.h>
#include <avr/interrupt.h>

#include "uart.h"
#include "ir_nec.h"

static int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,_FDEV_SETUP_WRITE);

static int uart_putchar(char c, FILE *stream)
{
	if (c == '\n')
	uart_putchar('\r', stream);
	loop_until_bit_is_set(UCSR0A, UDRE0);
	UDR0 = c;
	return 0;
}


int main(void)
{
	UART_Initialize();
	stdout = &mystdout;
	
	IR_Initialize();
	
	sei();
	
	while (1)
	{
		IR_ProcessData();	
		if (nec_new_data == true || nec_current_status == PACKET_RECVD_N_REPEAT_RECVNG)
		{
			nec_new_data = false;
			printf("nec_addrh=%u nec_addrl=%u nec_cmd=%u nec_cmdinv=%u\n",nec_current_packet.addr_h,nec_current_packet.addr_l,nec_current_packet.cmd,nec_current_packet.cmd_inv);
		}
	}
	
}

 

here is uart.h

#ifndef UART_H
#define UART_H

#define BAUD 57600
#define UBBR_VALUE (uint16_t)(F_CPU/(16UL*BAUD) - 1)

inline void UART_Initialize(void);

#endif

 

here is my uart.c

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>

#include "uart.h"

inline void UART_Initialize()
{
	UBRR0H = (uint8_t) (UBBR_VALUE >> 8);
	UBRR0L = (uint8_t) UBBR_VALUE;
	UCSR0B = (1 << RXEN0) | (1 << TXEN0);
	UCSR0C = (1 << UPM01) | (1 << UCSZ01) | (1 << UCSZ00) | (1 << USBS0); 
	//STOP BIT 2 DATA 8 BIT PARITY EVEN 
}



 

here is ir_nec.h

#ifndef IR_NEC_H
#define IR_NEC_H

#define IR_TSOP_DDR DDRB 
#define IR_TSOP_PIN 0

#define IR_START_TIME_H 30000
#define IR_START_TIME_L 25000
#define IR_LOW_TIME_H 2400
#define IR_LOW_TIME_L 1800
#define	IR_HIGH_TIME_H 4800
#define IR_HIGH_TIME_L 4000
#define IR_REPEAT1_TIME_H 24000
#define IR_REPEAT1_TIME_L 20000
#define IR_REPEAT2_TIME_H 65000
#define IR_REPEAT2_TIME_L 62000

#define IR_ICR_BUFFER_SIZE 20

struct nec_packet{
	uint8_t addr_l;
	uint8_t addr_h;
	uint8_t cmd;
	uint8_t cmd_inv;
};

struct circular_q{
	uint16_t buffer[IR_ICR_BUFFER_SIZE];
	uint8_t read_index;
	uint8_t write_index;
};

enum circular_q_status{
	EMPTY = 0,
	OK,
	OVERFLOW
};

enum nec_status{
	PACKET_RECVD = 0,
	PACKET_RECVD_N_REPEAT_RECVNG,
	IDLE,
	TIMING_ERR,
	CHKSM_ERR
};

extern volatile struct nec_packet nec_current_packet;
extern volatile struct circular_q icr_buffer;
extern volatile enum nec_status nec_current_status;
extern volatile enum circular_q_status icr_buffer_status;
extern volatile bool nec_new_data;
	
inline void IR_Initialize(void);
inline void IR_DeInitialize(void);
void IR_ProcessData(void);
inline void IR_WriteBuffer(uint16_t data);
uint16_t IR_ReadBuffer(void);
void IR_FlushBuffer(void);

#endif

 

here is ir_nec.c

#include <avr/io.h>
#include <string.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <stdbool.h>
#include <util/delay.h>
#include <stdio.h>

#include "ir_nec.h"

volatile struct nec_packet nec_current_packet = 
{
	.addr_l = 0,
	.addr_h = 0,
	.cmd = 0,
	.cmd_inv = 0
	};

volatile struct circular_q icr_buffer =
 {
	.buffer = {0},
	.read_index = 0,
	.write_index = 0
	};

volatile enum nec_status nec_current_status = IDLE;
volatile enum circular_q_status icr_buffer_status = EMPTY;
volatile bool nec_new_data = false;

static volatile uint8_t nec_current_state = 0;
static volatile uint8_t repeat_timer = 0;

inline void IR_Initialize()
{
	TCCR1B = (1 << ICNC1) | (1 << CS11); 
	//PRESCALER SET TO 8, NEGATIVE EDGE DETECTION ENABLE AND NOISE CANCELLER ENABLED
	
	TIMSK1 = (1 << ICIE1) | (1 << TOIE1);
	//ENABLE INPUT CAPTURE AND TIMER OVERFLOW INTERUPT
}

inline void IR_DeInitialize()
{
	TCCR1B = 0;
	TIMSK1 = 0;
}

ISR (TIMER1_CAPT_vect)
{
	TCNT1 = 0;
	repeat_timer = 0;
	IR_WriteBuffer(ICR1);
}

ISR(TIMER1_OVF_vect)
{
	if (nec_current_status == PACKET_RECVD_N_REPEAT_RECVNG)
		repeat_timer++;
		
	if (repeat_timer == 4)
	{
		nec_current_state = 0;
		nec_current_status = IDLE;
	}
}

void IR_FlushBuffer(void)
{
	ATOMIC_BLOCK(ATOMIC_FORCEON)
	{
		memset((void *)icr_buffer.buffer,0,sizeof(icr_buffer));
		icr_buffer.read_index = 0;
		icr_buffer.write_index = 0;
		icr_buffer_status = EMPTY;
		nec_current_state = 0;
	}
}

inline void IR_WriteBuffer(uint16_t data)
{
	icr_buffer.buffer[icr_buffer.write_index] = data;
	
	if (icr_buffer.write_index == IR_ICR_BUFFER_SIZE - 1)
		icr_buffer.write_index = 0;
	else
		icr_buffer.write_index++;
		
	if (icr_buffer.write_index == icr_buffer.read_index)
		icr_buffer_status = OVERFLOW;
	else
		icr_buffer_status = OK;			
}

uint16_t IR_ReadBuffer()
{
	uint16_t icr_copy;
	
	ATOMIC_BLOCK(ATOMIC_FORCEON)
	{
		icr_copy = icr_buffer.buffer[icr_buffer.read_index];
		
		if (icr_buffer.read_index == IR_ICR_BUFFER_SIZE - 1)
		icr_buffer.read_index = 0;
		else
		icr_buffer.read_index++;
		
		if (icr_buffer.read_index == icr_buffer.write_index)
		icr_buffer_status = EMPTY;
		else
		icr_buffer_status = OK;
	}	
	
	return icr_copy;
}

void IR_ProcessData()
{
	uint16_t icr_copy;
	
	if (icr_buffer_status == OK)
	{
		icr_copy = IR_ReadBuffer();
		nec_current_state++;
		
		if (nec_current_state == 2)
		{
			if (!(icr_copy <= IR_START_TIME_H && icr_copy >= IR_START_TIME_L))
			{
				nec_current_state = 0;
				nec_current_status = TIMING_ERR;
			}
		}
		else if (nec_current_state <= 34 && nec_current_state >=  3)
		{
			if (icr_copy <= IR_HIGH_TIME_H && icr_copy >= IR_HIGH_TIME_L)
			{
				if (nec_current_state <= 10)
					nec_current_packet.addr_l |= (1 << (nec_current_state - 3));
				else if (nec_current_state <= 18)
					nec_current_packet.addr_h |= (1 << (nec_current_state - 11));
				else if (nec_current_state <= 26)
					nec_current_packet.cmd |= (1 << (nec_current_state  - 19));
				else
					nec_current_packet.cmd_inv |= (1 << (nec_current_state - 27));
			}
			else if (icr_copy <= IR_LOW_TIME_H && icr_copy >= IR_LOW_TIME_L)
			{
				if (nec_current_state <= 10)
					nec_current_packet.addr_l &= ~(1 << (nec_current_state - 3));
				else if (nec_current_state <= 18)
					nec_current_packet.addr_h &= ~(1 << (nec_current_state - 11));
				else if (nec_current_state <= 26)
					nec_current_packet.cmd &= ~(1 << (nec_current_state - 19));
				else
					nec_current_packet.cmd_inv &= ~(1 << (nec_current_state - 27));
			}
			else
			{
				nec_current_state = 0;
				nec_current_status = TIMING_ERR;
			}
		}
		else if (nec_current_state == 35)
		{
			if (nec_current_packet.cmd == (unsigned char)~(nec_current_packet.cmd_inv))
			{
				nec_current_status = PACKET_RECVD;
				nec_new_data = true;
			}
			else
			{
				nec_current_state = 0;
				nec_current_status = CHKSM_ERR;
			}
		}
		else if (nec_current_state == 36)
		{
			if (!(icr_copy <= IR_REPEAT1_TIME_H && icr_copy >= IR_REPEAT1_TIME_L))
			{
				if (icr_copy <= IR_START_TIME_H && icr_copy >= IR_START_TIME_L)
				{
					nec_current_state = 2;
				}
				else
				{
					nec_current_state = 0;
					nec_current_status = TIMING_ERR;
				}
			}
		}
		else if (nec_current_state == 37)
		{
			if (icr_copy <= IR_REPEAT2_TIME_H && icr_copy >= IR_REPEAT2_TIME_L)
			{
				nec_current_state = 35;
				nec_current_status = PACKET_RECVD_N_REPEAT_RECVNG;
			}
			else if (icr_copy <= IR_START_TIME_H && icr_copy >= IR_START_TIME_L)
			{
				nec_current_state = 2;
			}
			else
			{
				nec_current_state = 0;
				nec_current_status = TIMING_ERR;
			}
		}
	}
	else if (icr_buffer_status == OVERFLOW)
	{
		IR_FlushBuffer();
	}
}

 

the compiler gives me an error that function declared but never defined

I'm using as 7.0

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

An inline function needs to be defined in the .h file.

 

Edit: Also F_CPU needs to be defined in the modules where it is used (by delay.h and in UBBR_VALUE).

It would be preferable to define it in the Project/Properties/Toolchain/Compiler/Symbols/Defined symbols as "F_CPU=16000000UL"

David

Last Edited: Sat. Jul 4, 2020 - 02:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Doesn't make a difference still getting the error

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try this for uart.h:

#ifndef UART_H_
#define UART_H_

#define BAUD 57600
#define UBBR_VALUE (uint16_t)(F_CPU/(16UL*BAUD) - 1)

inline void UART_Initialize(void)
{
    UBRR0H = (uint8_t) (UBBR_VALUE >> 8);
    UBRR0L = (uint8_t) UBBR_VALUE;
    UCSR0B = (1 << RXEN0) | (1 << TXEN0);
    UCSR0C = (1 << UPM01) | (1 << UCSZ01) | (1 << UCSZ00) | (1 << USBS0);
    //STOP BIT 2 DATA 8 BIT PARITY EVEN
}

#endif

and delete uart.c

 

Similarly do this for the functions  IR_Initialize, IR_DeInitialize, & IR_WriteBuffer in ir_nec.h (removing them from ir_nec.c).

 

... OR you could just remove the "inline" from all of these (and suffer the call overhead).

 

Edit: typo

Edit2: Please note, I have not checked the validity of the contents of the function UART_Initialize().

David

Last Edited: Sat. Jul 4, 2020 - 02:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is why it's best to design your software - and its structure - before you start throwing code into your editor!

 

It's a lot harder to tidy up an unstructured blob than to make it well-structured from the outset!

 

jeet55 wrote:
Doesn't make a difference still getting the error

You need to show what you actually did!

 

For how to define F_CPU in the Project Properties, see: https://www.avrfreaks.net/commen... and follow the links

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

frog_jr wrote:
remove the "inline" from all of these (and suffer the call overhead)

But a name like "UART_initialise" suggests something that will only ever be called once anyhow - so any "call overhead" is unlikely to be an issue?

 

Also note that GCC is quite smart enough to spot when things can be inlined without having the 'inline' keyword ...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so any "call overhead" is unlikely to be an issue

Quite true and valid comments; however, I don't "know" that the functions (other than initialization) will only be used where the compiler can figure out inlining "can/should" be done.

David

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

From your previous threads it seems that you have some kind of addiction to the "inline" keyword. Suggest that you don't use it at all. Write "normal" C with definitions in .c files and declarations in .h. Only consider adding inline functions later if some special part of the code absolutely demands it (unlikely!).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
From your previous threads it seems that you have some kind of addiction to the "inline" keyword. Suggest that you don't use it at all. Write "normal" C with definitions in .c files and declarations in .h. Only consider adding inline functions later if some special part of the code absolutely demands it (unlikely!).
Why not just tell him he is too foolish to own a compiler?

 

Some rather simple rules work:

An inline function to be used in more than one .c (top level) file should be declared and defined in a .h (header) file.

An inline function to be used in precisely one .c file may be declared static.

Declaring and defining it in that file works.

 

BTW I've read that the linked-to story was just a fantasy written by a tech support person

 

Rude comment removed - moderator

Moderation in all things. -- ancient proverb

Last Edited: Sat. Jul 4, 2020 - 07:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skeeve wrote:
An inline function to be used in more than one .c (top level) file should be declared and defined in a .h (header) file.

should probably also be declared 'static' in the header

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the other (now locked) thread, clawson wrote:
start by learning C programming. Put the AVR off to obe side for the time being until you've done that.

 

https://www.avrfreaks.net/commen...

 

 

This advice is often repeated, and by many people. It would be wise to heed it.

 

For some 'C' learning & reference materials, see:

 

http://blog.antronics.co.uk/2011/08/08/so-youre-thinking-of-starting-with-c/

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jeet55 wrote:

the compiler gives me an error that function declared but never defined

 

Where is the full text of the error? Where is the name of the function the compiler complains about? Why is this information missing from the original post?

 

---

 

As for most of the answers regarding inline functions presented here so far: people apparently fail to understand that inlining approach used in C is fundamentally different from that of C++. Most of the advice here seems to be applicable to C++, while the program is obviously written in C.

 

In C, regardless of where the function is defined (header file or implementation file), if an inline function has external linkage, it is the responsibility of the author of the code to emit a unique non-inline external definition of that function. Failing to do so will result in linkage errors if the compiler decides to leave some calls non-inlined. In this code I see lots and lots of `inline` functions with external linkage, but no effort is made to provide external definitions for these functions. In C an external definition for an inline function is emitted through `extern inline` combination.

 

Of course, the first question here is whether these functions even need external linkage. Most of them should be `static inline`, it seems.

Dessine-moi un mouton

Last Edited: Sat. Jul 4, 2020 - 04:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

It's a lot harder to tidy up an unstructured blob than to make it well-structured from the outset!

I was trying to create an unstructured blob, but all of my advanced planning wouldn't let me---everything kept falling into perfect place & I was barely able to get any compile errors. crying 

I may try again later.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sat. Jul 4, 2020 - 08:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skeeve wrote:

clawson wrote:
From your previous threads it seems that you have some kind of addiction to the "inline" keyword. Suggest that you don't use it at all. Write "normal" C with definitions in .c files and declarations in .h. Only consider adding inline functions later if some special part of the code absolutely demands it (unlikely!).
Why not just tell him he is too foolish to own a compiler?
Not rude? Foolish is less rude than stupid?
Quote:
Some rather simple rules work:

An inline function to be used in more than one .c (top level) file should be declared and defined in a .h (header) file.

An inline function to be used in precisely one .c file may be declared static.

Declaring and defining it in that file works.

 

BTW I've read that the linked-to story was just a fantasy written by a tech support person

 

Rude comment removed - moderator

Which moderator?

Also, removed and edited are not the same.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

It's a lot harder to tidy up an unstructured blob than to make it well-structured from the outset!

I was trying to create an unstructured blob, but all of my advanced planning wouldn't let me---everything kept falling into perfect place & I was barely able to get any compile errors. crying 

I may try again later.

You were after errors or just warnings?

A couple of #warning or #error texts might might help throughout your code. That should ensure you are done rather quicky with this project.