atmega16 serial communication not working (both uart_send and uart_receive) - c

I'm trying to communicate between a BLE using Atmega16 with android app(Just to send a character and receive it back).
I'm able to transfer data between BLE with arduino and app but when i'm using atmega16 micro-controller it's not working. When i'm trying to send a character and recieve it back some characters are getting back exactly (0 to 9,q,w,r,t,y,u,p,z,s,x,v,:,^,=,?,;), but others are not.
I think the problem is with my baud rate and CPU frequency. I tried many combinations but none of them are returning whole charcters back exactly.
These are my uart initialization and Interrupt functions
I've used CPU frequency 14.7456MHz and Baud rate 230.5k. I tried using baud rate 9600 at 8Mhz frequency but for these values random garbage values are coming back.
#define F_CPU 14745600UL
#define BAUDRATE 230500UL
#define BAUD_PRESCALE ((F_CPU / (BAUDRATE * 16))) - 1
void uart_init() {
UBRRL = (unsigned char) (BAUD_PRESCALE);
UBRRH = (unsigned char) (BAUD_PRESCALE >> 8);
UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE);
UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1);
// Need to disable JTAG twice. Read spec sheet for details.
// http://www.avrfreaks.net/comment/618701#comment-618701
MCUCSR = (1 << JTD);
MCUCSR = (1 << JTD);
}
ISR(USART_RXC_vect) {
uint8_t c = UDR;
UDR = c;
PORTA = c;
}
Any help!!

We need to change fuse bits not only when using external crystal/resonator, but we also have to change fuse bits when we are using internal RC oscillator. The default configuration of fuse bits is for frequency 1Mhz. For different frequencies of internal RC oscillator we need to set the fuse bits accordingly. This fuse bit calculator will be helpful.
How to set fuse bits is explained in this blog.
I don't know earlier that we have to set different fuse bit configurations for different internal frequencies also.
Finally i solved my problem with your support. Next i have to transfer strings and much more.
Thank you all.

If you are writing it in Atmel studio. It has terminal window exstension (it worked on 6.0 version, on 7.0 I don't know now).
If you're not using Atmel studio, than open some terminal and listen what's coming. If you are getting dummy data, it means you haven't configured fuse bits properly as is answered upper.
If you're using Atmel studio, I suggest use some STK500 like programmer and integrate it in Atmel studio. Program devices from there. It's more comfortable and fuse bit settings is easy from there.
I see you're using 14745600 hz oscillator. You have to set fuse bits for External high frequency oscillator ready.
If you want to disable JTAG it's possible to disable it from fuse bits.

Related

Proper use of SPI functions in RP2040 C/C++ SDK with PGA2310 volume control IC

I've been working on a project where I use a PGA2310 volume control IC to set the volume of an audio signal. The chip's interface is supposedly SPI, but no matter how much I try, I just can't seem to get it right. The chip takes a 16 bit word over SPI that contains the left and right channel volume information.
I'm wondering if I am using the sdk all wrong and my code is whacked.
I guess my question is: Am I setting up and using the SPI functions correctly?
Here is my code
/**
* SPI interface for PGA2310 volume control ic
*/
#include "pico/stdlib.h"
#include "hardware/spi.h"
#include "pico/time.h"
const int CS = 0;
const int SDI = 1;
const int SCLK = 2;
const int LED_PIN16 = 16;
const int LED_PIN25 = 25;
uint16_t PGA2310();
uint16_t PGA2310() {
int baud = 1600000;
// SPI inistalization
spi_init(spi0, baud);
spi_set_format(spi0, 16, SPI_CPOL_0 , SPI_CPHA_0, SPI_MSB_FIRST);
// Sets SPI pins
gpio_set_function(CS, GPIO_FUNC_SPI);
gpio_set_function(SDI, GPIO_FUNC_SPI);
gpio_set_function(SCLK, GPIO_FUNC_SPI);
// Sets LED pins
gpio_init(LED_PIN16);
gpio_set_dir(LED_PIN16, GPIO_OUT);
gpio_init(LED_PIN25);
gpio_set_dir(LED_PIN25, GPIO_OUT);
// Data to send to chip. only sending first 8 bits for right channel.
// This is because I am currently just testing the output of the right channel
uint16_t high = 255;
uint16_t low = 100;
// Test by toggling between high and low volume states with LED indicators
while (true) {
gpio_put(LED_PIN25, 1);
spi_write16_blocking(spi0, &high, 1);
sleep_ms(2000);
gpio_put(LED_PIN25, 0);
spi_write16_blocking(spi0, &low, 1);
sleep_ms(2000);
}
}
I've tried a bunch of different methods that I found online for using SPI with the pico SDK. I've tried just sending 8 bits.
Let me know if more info is needed.
As explained in comments, SPI normally consists of 4 signals: /SS, SCLK, MOSI and MISO.
/SS = slave select, also known as chip select. Almost always active low.
SCLK = serial clock.
MOSI = Master Output Slave Input. The main data line. Your MCU seems to call this SDO (serial data out?).
MISO = Master Input Slave Output. Optional signal for duplex (two way) communication SPI. Your MCU seems to call this SDI (serial data input).
In this case the MCU is the master so you should be using MOSI/SDO. A MCU is almost always the master, except when communicating with other MCUs.
Additionally, always double check which CPOL and CPHA settings that the slave expects. Getting these wrong is a classic problem and can lead to subtle "clock skew" problems where everything works fine most of the time, then fail and give corrupt data intermittently.
The names you pick for variables/constants in C code do not have any effect on the hardware and they disappear as soon as the code is compiled. The most important thing is that you understand how the hardware works, read the documentation for the RP2040 SDK functions you are calling, and then pass the correct values to the RP2040 SDK functions.
The biggest problem is that you need to rethink every pin assignment. The RP2040 hardware SPI pin functions are defined in column F1 of the "GPIO Functions" section of the RP2040 datasheet. Here is an excerpt from that table:
This table tells us, for example, you cannot use pin 0 as the SPI0 CS function. If you assign that pin to be an SPI pin, it will be the SPI0 RX (data receiving) pin.
At a minimum, you need to pick one pin to be the SPI0 SCK pin and another to be the SPI0 TX pin, and you must connect those pins from the RP2040 to the equivalent pins on your device. Then you might also need to pick an RP2040 pin to control the CS pin on your device, if it has one. On the RP2040 side, this pin would be configured as a GPIO output pin and you would drive it low or high to enable your device. Refer to your device's datasheet for details about what signals it expects on its inputs and then use an oscilloscope to make sure you are generating compliant signals.
Another problem is that the spi_write16_blocking is probably modifying your high and low variables, so you will probably need to set those to the right values before each time that you use them. (So there is no point in having two different variables like that, just have one.)

STM32 Bare Metal C - Can't get LED to work

So I'm currently following a course for the STM32 Microprocessor however, I seem to fail at even the most basic thing: turning a LED on. The complete code is at the bottom of this post.
Important:
The hardware is functioning properly.
I am using a STM32L432KC.
First of all, we have to figure out on what pin the built-in LED is. According to the manufacturers manual, the LED should be on pin D13 (PB3).
Okay so we're looking for PB3. According to the datasheet of the STM32L432KC, PB3 is on the B port and therefore connected to the high performance bus as suggested in the image below.
Cool. So our bus is AHB2 and we're working with GPIOB. Now we have to enable the clock on that bus using the RCC_AHB3ENR register. Now, this is the part where I'm probably going to make mistakes (as this post otherwise wouldn't exist), so please pay close attention. If I understand correctly, I want bit 1 to be set to 1 as this indicates that 'GPIOBEN' is set to 'IO port B clock enabled.'.
This leads me to believe that I should set the bus register as follows:
RCC->AHB2ENR |= 0x2;
Next up I have to set the mode of the GPIO pin to output. According to the course and my documentation, this is done using GPIOx_MODER.
This leads me to believe that I should set the GPIO mode as follows:
GPIOB->MODER |= 0x40;
And last but not least to turn the actual LED on we have to set the output data register which is GPIOx_ODR.
This leads me to believe that I should set the data as follows:
GPIOB->ODR = 0x8;
I'm not sure where I'm going wrong but this is the first time I'm working with registers on such a deep level. I must be overlooking something but I've tried multiple examples and had no success. All help is appreciated.
This is the complete code:
// PB3 - User LED
// RCC->AHB2ENR
// GPIOx_MODER
// GPIOx_ODR
#include "stm32l4xx.h"
int main(void)
{
RCC->AHB2ENR |= 0x2;
GPIOB->MODER |= 0x40;
while(1)
{
GPIOB->ODR = 0x8;
}
}
Your mode register is not configured correctly. Your line of code
GPIOB->MODER |= 0x40;
can only set bits, it cannot clear them. And you have too many bits set, as the reset value of each pair is 11 and the entire register is FFFF FFFF for ports C-E, FFFF FEBF for port B.
You should use
GPIOB->MODER = (GPIOB->MODER & 0xFFFFFF3F) | 0x00000040;
although because the reset state is guaranteed, this will also work:
GPIOB->MODER &= 0xFFFFFF7F; // equivalently, ~0x0080
The note in the documentation of 11 analog mode (reset state) is not accurate for all pins. Several are in 10 alternate function mode at reset, including PB3. So you need to both clear one bit and set one.

When on 4 bit data mode, is it possible to use the other 4 bits for other stuff?

So im writing a C program to interface an LCD on 4 bit data mode. However, I was wondering if I could use the other 4 bits to do something else like an external interrupt.
To be more specific, Im using PORTD for the data lines on the arduino however I also need pin PD2 to use the INT0 interrupt (pushbutton). In my program I noticed I kept setting the lower 4 bits to 0 when sending commands:
PORTD = cmd & 0xf0;
flashLCD();
PORTD = (cmd & 0x0f) << 4;
This works perfectly but it sets the other bits to 0. This is called on a timer which means Im sending commands repeatedly. Therefore, I tried saving the previous value of the register and append it with some bitwise operations:
uint8_t initial_state = PORTD;
PORTD = (cmd & 0xf0) | (initial_state & 0x0f);
flashLCD();
PORTD = ((cmd & 0x0f) << 4) | (initial_state & 0x0f)
It sends the cmd on the LCD, however it still wont respond to the interrupt. I wanted to know if theres something Im not taking into consideration or if my logic is incorrect. Thanks.
Edit: Nvm I figured it out. My LCD library resetted the port register to 0 always even when on 4 bit mode so the other unused ports were being reset as well. I just changed the library so that I can use the other ports when on 4 bit mode.
You correctly noted that other bits can be preserved by using the bitwise operations
PORTD = (PORTD & 0x0F) | (high_bits << 4);
But! this line is going to be compiled into several machine instructions:
load PORTD value into a register
perform bitwise AND on the register
load high_bits into another register
perform other calculations (left shift on the high bits etc.)
perform bitwise OR
store the result back into PORTD
Let's imagine, somewhere between 1 and 6 an interrupt fires, it stop the code execution, and it changes lower bits of PORTD. After the interrupt routine completes, the program continues to execute and it will rewrite all 8th bits of PORTD by what was stored in the registers before the interrupt, thus overwriting lower bits of PORTD, discarding all changes made in the interrupt routine.
So, there are two approaches to make write operation to PORTx atomic.
First: just disable interrupt for the time of PORTx register update:
uint8_t old_sreg = SREG; // save SREG register (including I flag)
cli(); // clear I flag, thus prohibiting interrupts
PORTD = (PORTD & 0x0F) | (high_bits << 4); // perform the operation
SREG = old_sreg; // restoring SREG and I flag, if it was set before
Second approach works only on new AVR cores (eg. ATmega328, 1284, 2560 etc), but will not work on older ones (ATmega8, 32 etc). Refer to the datasheet, I/O-Ports -> Ports as General Digital I/O -> Toggling the Pin section.
Writing ones into bits of PINx will invert corresponding bits of PORTx. Using it, it is possible to update only required bits of PORTx register, leaving other intact, thus removing need of locking out interrupts. It may be useful in time-critical environment, where interrupt should fire as quick as possible.
PIND = (PORTD ^ (high_bits << 4)) & 0xF0;
Of course it will work if it guaranteed the interrupt may change only other (in this example - lower) bits of the PORTD. If the interrupt can also write in the same bits, then this may cause unexpected results, so, be careful.
I do not know the controllers (ATmega/AVR or whatever) used on Arduino and you do not even specify, which one you use.
But usually, ports and port pins can be configured to have either input or output mode. Since you give out 4 bits over PORTD, I assume, the whole 8bit port (all port pins) are configured as output.
You should consider your manual, if certain pins of the whole port can be output pins while others can be input pins at the same time and how.
Be careful switching input/output of a whole port in between, it could have side effects, e.g. unwanted H-L / L-H transitions. I had this once with an 8255 output chip, causing resets of my graphic LCD, due to a connected reset line of the LCD.

Arduino timer seems to be crashing?

For an exhibition with some interactive installations, I have to create a system that reads data from three ultrasonic PING sensors and has a DMX dimmer connected at one output.
So I took my Arduino Mega board, built some hardware around it (signal inverter for DMX) and tested the DMX dimmer using the library DmXSimple. It works fine!
Next step: testing the PING sensors. I used the library NewPing, and connected the sensors. It works fine!
Now both together, in one program: Importing both libraries, using the same codes. It doesn't work!
Timer collision? Well...anyway - I have no idea on how to solve that. What should I do? If it's a timer issue (that is, both libraries call the same timer), I really don't know how to modify the libraries to get it working.
There are two timers on the Arduino, and you may be able to make both works aside. DmxSimple explicitly says it uses the timer #2, whereas it is not clear for NewPing. But the NewPing library can work without using a timer. You can make the DmxSimple work using its timer (which is mandatory for close-to-real-time interaction with its bus), whereas you can handle the sonar ping in the loop function:
void loop() {
int dst = sonar.ping_cm();
delay(50);
DmxSimple.write(1, dst);
}
There you shouldn't have timers conflicting.
Looking at the source code of NewPing, it uses Timer2 if you use the timer_us()/timer_ms() functions, but no timer otherwise. But if you run it on an Arduino Leonardo (or Arduino Micro or any other ATmega32U4 based microcontroller), it will use Timer4 which is not conflicting with DmxSimple.
If you want to patch the NewPing library to use Timer3, you may want to replace this in NewPing.cpp:
OCR2A = 249;
TIMSK2 |= (1 << OCIE2A);
with
OCR3A = 640;
TIMSK3 |= (1 << OCIE3A);
and in stop_timer:
TIMSK2 &= ~(1 << OCIE2A);
with
TIMSK3 &= ~(1 << OCIE3A);

beginning with winAVR

I have 20 odd years in programming starting from pascal 7 to delphi. I want to start programming micro controllers using C and the tool most electronics kit recommend is winAVR with programmers notebook. I have installed the software and would like to start compiling code and I'm lost to say the least and can't find any simple documentation to get myself onto a track where I can start testing code. Can anyone offer some good starter material?
Whereas for PC's the usual first program is "Hello, World!", in the embedded world (one lacking displays, as least to start with, the equivalent is the blinky led: you attach a LED to some output pin of your processor (don't forget the current-limiting resistor!: you need a resistor in series with the LED), and you make the LED blink. You can find plenty of blinky LEDs for AVR, but we can write one right here:
// The next define tells delay.h what your CPU speed is, assuming 1Mhz
#define F_CPU 1000000UL
#include <util/delay.h>
main() {
while(1) { // loop forever
DDRB = 0xFF; // Set the direction of all pins
// on port B to OUTPUT (can change to some other port)
PORTb = 0xFF; // Set all pins on port B high (can change to some other port)
_delay_ms(1000); // Wait one second;
PORTb = 0x00; // Set all pins on port B low (can change to some other port)
_delay_ms(1000); // Wait one second;
}
}
It should compile on WinAVR, and load correctly. Change PORTB and DDRB to some other port of you'd like. Note that this program changes all the pins on that port: so if your port B has 8 pins, all of them will blink a led hooked up to them. Don't forget the current-limiting resistors, and that LEDs are directional: they only work when plugged in one way, and not the other.

Resources