Only 4 letters are showing up. Like in the example, I send the string "abcdef", but it only shows the 4 letters "abcf". I don't know why the other letters don't show up. I'm using Atmega8 and Bray terminal. I'm already following from the datasheet [http://ww1.microchip.com/downloads/en/DeviceDoc/21822E.pdf][1]. But I've already found a dead end.
Implementation of functions
#include <avr/io.h>
#include <math.h>
#include <util/delay.h>
#define DD_SS PINB2 //Chip select ON RC2
#define DD_MOSI PINB3 // Master out - Slave in pin
#define DD_MISO PINB4 // Master in - Slave out pin
#define DD_SCK PINB5 // Clock from master
#define DDR_SPI PORTB // DDR_SPI
void serial_init(void)
{
UBRRH = 0x00;
UBRRL = 7;
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0)|(1 << UCSZ1);
UCSRB = (1 << RXEN) | (1 << TXEN)| (1<<RXCIE);
}
unsigned char Usart_Receive(void)
{
while ((UCSRA & (1 << RXC)) == 0) {};
return UDR;
}
void Usart_Transmit(unsigned char c)
{
PORTD= 0b00000100; //RTS Enable
while ((UCSRA & (1 << UDRE)) == 0) {};
UDR = c;
PORTD= 0b00000000; //RTS Disable
}
void SPI_MasterInit(void)
{
DDRB = 0b00101100;
DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK);
SPCR = 0b01010000;
SPSR = 0b00000001;
}
unsigned char spi_transfer(volatile char data)
{
SPDR = data;
while(!(SPSR & (1<<SPIF)));
{
}
return SPDR;
}
void SPI_MasterTransmit (uint8_t Data)
{
uint16_t address;
SPCR = (1<<SPE) | (1<<MSTR) | (0<<CPHA);
DDR_SPI &= ~(1<<DD_SS); // Select EEPROM
spi_transfer(WREN); // Send WRITE_ENABLE command
DDR_SPI |= (1<<DD_SS); // Release EEPROM
DDR_SPI &= ~(1<<DD_SS); //ss goes low
spi_transfer(WRITE); // write data to memory
spi_transfer (address>>8);
spi_transfer (address);
spi_transfer(Data);
DDR_SPI |= (1<<DD_SS); //ss goes high
}
unsigned char SPI_MasterReceive(uint16_t address)
{
unsigned long data;
SPCR = (1<<SPE) | (1<<MSTR) | (0<<CPHA);
//waitBusy();
DDR_SPI &= ~(1<<DD_SS); //ss goes low
spi_transfer(READ); //enable write operation
spi_transfer (address>>8);
spi_transfer (address);
data = spi_transfer(0xff);
DDR_SPI |= (1<<DD_SS); //goes high
return data;
}
and this is main function
int main (void)
{
char data;
unsigned char address;
serial_init();
SPI_MasterInit();
while(1)
{
data = Usart_Receive();
_delay_ms(10);
SPI_MasterTransmit(data);
_delay_ms(10);
data = SPI_MasterReceive(address); //read data from the memory
_delay_ms(10); //pause for readability
Usart_Transmit(data);
}
return 0;
}
I hope someone can help me here. :)
Your USART is transmitting too fast for your receiver. By your fourth time through the main loop, the USART transmitter has overwritten the "d" with "e" and then with "f".
A way to get around this is to use interrupts for receiving data, instead of polling like you are doing now. But you won't be able to write to the EEPROM as fast as the interrupts come. Instead, you should queue up the letters into a circular array or linked list or some other data structure as they arrive, and then write them to EEPROM in the main loop as time allows.
Note that this solution will only help with bursty data; you save up the burst and then deal with it as you can. But if the USART is continuously too fast, then you will never be able to keep up.
To debug this issue you need to localise the place of problem and to do this you have to split your experiment on sub-tasks.
One of them is to check UART separately, the code gets here like:
while(1)
{
data = Usart_Receive();
_delay_ms(10);
Usart_Transmit(data);
}
The second one is to check SPI apart from UART stuff if you have JTAG, or altogether if you get managed with making UART working. For the separate SPI checking just comment Usart_Receive(); and Usart_Transmit(data); initialize data with anything and probably increment it in the while. Hope this idea helps.
Related
I wrote up a function to connect via UART and print a string for debugging purposes. But my logic does not add up somehow... I see the line "Random Number" printed in the console but blazingly fast... no matter what I add for a _delay_ms value, it is not usable. Did I miss out on anything?
Why is my delay function not having any influence on the output on the serial terminal?
void initUSART(void) {
#define BAUDRATE ((F_CPU) / (BAUD * 8UL)-1) // Set Baud Rate Value for UBRR
// Set register
UBRR0H = (BAUDRATE >> 8);
UBRR0L = BAUDRATE;
UCSR0A |= (1 << U2X0);
// Enable USART transmitter and receiver
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
// Set 8 data bits and 1 stop bit
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
}
void transmitByte(uint8_t data) {
// Wait for empty transmit buffer
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = data;
}
void printString(const char myString[]) {
uint8_t i = 0;
while (myString[i]) {
transmitByte(myString[i]);
i++;
}
}
int main(void)
{
setup();
randomSeed(adcRead(0));
while (1)
{
printString("Random Number:\n");
_delay_ms(100000);
}
return (0);
}
When I use \r\nat the end of the string, the output gets really strange:
When I try this test code everything works as expected, the LED blinks every second. I really don't see where the difference is, as it is the same function.
/* Blinker Demo */
// ------- Preamble -------- //
#include <avr/io.h> /* Defines pins, ports, etc */
#include <util/delay.h> /* Functions to waste time */
int main(void) {
// -------- Inits --------- //
DDRB |= 0b00000001; /* Data Direction Register B:
writing a one to the bit
enables output. */
// ------ Event loop ------ //
while (1) {
PORTB = 0b00000001; /* Turn on first LED bit/pin in PORTB */
_delay_ms(1000); /* wait */
PORTB = 0b00000000; /* Turn off all B pins, including LED */
_delay_ms(1000); /* wait */
} /* End event loop */
return 0; /* This line is never reached */
}
I have a problem to communicate from an Atmega3216PU to a at42qt2100.
The datasheets are: Atmega32PU16 and AT42QT2100
This is my code:
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#define F_CPU 16000000
#define UART_BAUD_RATE 9600
#define UART_BAUD_REGISTERS (((F_CPU / (UART_BAUD_RATE * 16UL))) - 1)
int printCHAR(char character, FILE *stream)
{
while ((UCSRA & (1 << UDRE)) == 0) {};
UDR = character;
return 0;
}
FILE uart_str = FDEV_SETUP_STREAM(printCHAR, NULL, _FDEV_SETUP_RW);
void setup(){
// Init SIO
UCSRB |= (1 << RXEN) | (1 << TXEN);
UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1);
UBRRL = UART_BAUD_REGISTERS;
fprintf(&uart_str, "");
stdout = &uart_str;
printf("");
//Init spi
//set MOSI, SCK and SS output, all others input
DDRB |= (1<<DDB7)|(1<<DDB5)|(1<<DDB4);
SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0)|(1<<CPHA)|(1<<CPOL);
}
void loop(){
uint8_t data = 0b01000000; //Sending this sequence should return device id
printf("Sending: %d \n",data);
_delay_ms(10000);
PORTB &= 0b11101111; // SS auf LOW!! (Pin4)
SPDR = data;
while(!(SPSR & (1<<SPIF)));
PORTB |= (1<<PB4); // SS auf HIGH!! (Pin4)
printf("Receiving: %d \n",SPDR);
_delay_ms(10000);
}
void main(){
setup();
while(1){
loop();
}
}
I should get an answer from the at42qt2100 with the device id 108 but i always get 0. This ist the output: Sending: 64 Receiving: 0
Does anybody see a misconfiguration?
I did a quick overview of the AT42QT2100 datasheet that you reference and I see a couple of problems right away:
After SS is set low, the host must wait >2us (in Free Run mode) before starting SCK. You are immediately initiating a SPI transfer and, if you are running a 16MHz, that means you may be starting the transmission as soon as 62.5ns after setting SS low.
The datasheet also says that the host must send 3 data bytes within 10ms or the transaction will be treated as an error and the communication exchange will be reset. You are sending 1 byte and then waiting 20s before sending the next byte.
The datasheet says that the device settings become active after the 3 bytes have been sent. That means that 3 more bytes must be sent to get the response to your command.
You should be doing something more along the lines of this:
#define NUM_DATA_BYTES 3
void loop(){
uint8_t sendData[NUM_DATA_BYTES] =
{
0b01000000, /* Device Version Command and default values. */
0b00000000, /* Default Value for Byte 2. */
0b11000000, /* Default Value for Byte 3. */
};
uint8_t receiveData[NUM_DATA_BYTES] = { 0 };
uint8_t i;
PORTB &= 0b11101111; // SS auf LOW!! (Pin4)
/* Ensure that >2us delay requirement is met. Although, the
for() loop below will probably introduce enough delay. */
_delay_ms(1);
/* Send command data. */
for (i = 0; i < NUM_DATA_BYTES; i++)
{
SPDR = sendData[i];
while(!(SPSR & (1<<SPIF)));
}
PORTB |= (1<<PB4); // SS auf HIGH!! (Pin4)
/* Delay here may be unnecessary, but it ensures that timing
issues do not occur. */
_delay_ms(1);
PORTB &= 0b11101111; // SS auf LOW!! (Pin4)
_delay_ms(1);
/* Receive device response data. */
for (i = 0; i < NUM_DATA_BYTES; i++)
{
SPDR = sendData[i];
while(!(SPSR & (1<<SPIF)));
receiveData[i] = SPDR;
printf("Receiving byte %d: %d \n", (i + 1), receiveData[i]);
}
PORTB |= (1<<PB4); // SS auf HIGH!! (Pin4)
_delay_ms(10000);
}
I am sure this code is not perfect, but it should help to get you on the right track. Good luck!
I am trying to send data from the Msp430fr5969 Launchpad to the rn-52-ek so it can pass the data along through bluetooth.
#include <msp430.h>
void uartSend(unsigned char *pucData, unsigned char ucLength)
{
while(ucLength>0)
{
// Wait for TX buffer to be ready for new data
while(!(UCA1IFG & UCTXIFG));
// Push data to TX buffer
UCA1TXBUF = *pucData;
// Update variables
ucLength--;
pucData++;
}
}
void initUART()
{
/* Place UCA0 in Reset to be configured */
UCA0CTL1 = UCSWRST;
//Set BRCLK = SMCLK
UCA0CTL1 |= UCSSEL_2;
//Values found using table for 16Mhz and 115200 baudrate
UCA0BR0=8;
UCA0BR1=0;
UCA0MCTLW = 0xF7 << 8;
UCA0MCTLW |= 10 << 4;
UCA0MCTLW |= UCOS16;
//UCA0 out of reset
UCA0CTL1 &= ~UCSWRST;
}
int main(void) {
// disable watchdog timer
//------------------------
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
initUART();
unsigned char sendString[] = "Banana";
unsigned char length=6;
while(1)
{
uartSend(sendString,length);
}
return 0;
}
Nothing is happening when I run the above code, not even reading anything on the multimeter. What am I missing?
I know there are some bad practices, I just want to get it working and I'll add the interrupt based sending later.
You should set Port 2.5 as Tx for the UART
I am writing a code for a MCU until that will transmit data via UART (RS232).
[ATmega8A]
Currently, I am testing my code in Proteus:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <compat/twi.h>
#define FOSC 16000000 //Clock Speed
#define BAUD 9600 //Baud rate set to 9600
#define MYBRR FOSC/16/BAUD-1
void USART_Init (void)
{
UBRRH = (MYBRR >> 8); //Code for setting
UBRRL = MYBRR; //the baud rate
UCSRB = (1 << RXEN) | (1 << TXEN); //Enable receiver and transmitter
UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); //Frame format setting: 8 Data, 2 Stop bit
}
/* USART transmit function */
void USART_Transmit(unsigned char data)
{
while(!(UCSRA & (1 << UDRE))); //Wait until transmit buffer is empty
UDR = data;
}
/* USART receive function */
unsigned char USART_Receive(void)
{
while(!(UCSRA & (1 << RXC))); //Wait until data is received
return UDR; //Get the data from buffer and return it
}
and the test code in main:
int main(void)
{
unsigned char c;
while(1)
{
a = USART_Receive();
c = 10;
USART_Transmit(c);
_delay(10000);
}
}
In Proteus, the virtual terminal displays 0. However, I am expecting to see 10.
This is just one example, in general only the last digit/character is getting displayed on the virtual terminal.
I cannot explain this. Proteus bug or logic error?
Thank you for any advise.
UART data is sent only in ascii format...you have to convert the integer data to ascii format..use itoa() or do this one
int main(void)
{
unsigned char c;
unsigned char b;
while(1)
{
a = USART_Receive();
c = 10;
b=c;
b=c/10;
USART_Transmit(b+48);
b=0;
b=c%10;
USART_Transmit(b+48);
_delay(10000);
}
}
I am using the UART of Atmega169/AVR Butterfly for transmission to another board, baudrate 56700, no parity, 1 stopbit, no flow control. The oscillator is running at 7,3768Mhz (checked). I can transmit data successfully (checked with the other board and PC/HyperTerminal), but not receive any data - when running the debugger the configuration bits are all set correctly, but RXC is false constantly - I also checked if I can send data to myself (connected TXD to RXD and grounded), but without success. (Tried with ISR as well as polling)
Below are the relevant parts of the code, I hope you can deal with it - PORTB is used as output for testing with the oscilloscope (I know I could just use one pin, but there is nothing else on PORTB right now):
int main(void){
OSCCAL_Calibrate(); // calibrate the internal oscillator
int UBRR_VAL = ((F_CPU)/(BAUD*16)-1);
UART_Init(UBRR_VAL);
DDRB |= 0xFF;
PORTB = 0;
testCharSend();
while(1);
return 0;
}
void testCharSend()
{
char i = 'x';
while(1){
Uart_Tx(i);
}
}
void UART_Init(unsigned int baudrate)
{
// Set baud rate
UBRRH = (unsigned char)(baudrate>>8);
UBRRL = (unsigned char)baudrate;
UCSRA = 0;
// Enable receiver and transmitter
UCSRB = (1<<RXEN)|(1<<TXEN);
// Async. mode, 8bit, No parity, 1 stop bit (like CC2540)
UCSRC = (0<<UMSEL)|(0<<UPM0)|(0<<USBS)|(3<<UCSZ0)|(0<<UCPOL);
// enable receive interrupt
UCSRB |= (1<<RXCIE);
// flush UART
UART_Flush();
}
void UART_Flush( void )
{
unsigned char dummy;
while ( UCSRA & (1<<RXC) ) dummy = UDR;
}
void Uart_Tx(char data)
{
while (!(UCSRA & (1<<UDRE)));
UDR = data;
}
ISR (USART0_RX_vect)
{
PORTB ^= 0xFF;
char c = UDR;
}
OK, I tested the connections with an oscilloscope, the RXD line on the board was broken, switched the board and now it's working, so the code above is valid!