Main function's command repetition problem in C - c

I'm Noh.
I'm trying to control Microcontroller with C code.
And I'm using a code I got from GitHub. (Here's the link https://github.com/jwr/msp430_usi_i2c)
I encountered the problem that main function doesn't stop.
Even though there's no loop command in main, command flow repeats again and again.
I write command flow like below.
Write 00 → Write AF → Write 00 → Write 05 → Write 45 → Write 40 → Write 03 → Write B0 → Read EE
And you can see the command flow repeats from beginning to end.
Please refer to below code and the communication result.
#include <msp430.h>
#include <stdint.h>
#include "usi_i2c.h"
#include <stdio.h>
#include <stdlib.h>
// Internal state
static uint16_t const *i2c_sequence;
static uint16_t i2c_sequence_length;
static uint8_t *i2c_receive_buffer;
static uint16_t i2c_wakeup_sr_bits;
i2c_state_type i2c_state = I2C_IDLE;
static uint8_t status;
static inline void i2c_prepare_stop();
static inline void i2c_prepare_data_xmit_recv();
void i2c_send_sequence(uint16_t const * sequence,
uint16_t sequence_length,
uint8_t *received_data,
uint16_t wakeup_sr_bits) {
while(i2c_state != I2C_IDLE); // we can't start another sequence until the current one is done
while((status==0xEE)|(status==0xEF)) P1OUT |= 0x01;
P1OUT &= ~0x01;
i2c_sequence = sequence;
i2c_sequence_length = sequence_length;
i2c_receive_buffer = received_data;
i2c_wakeup_sr_bits = wakeup_sr_bits;
i2c_state = I2C_START;
USICTL1 |= USIIFG; // actually start communication
}
static inline void i2c_prepare_stop() {
USICTL0 |= USIOE; // SDA = output
USISRL = 0x00;
USICNT |= 0x01; // Bit counter= 1, SCL high, SDA low
i2c_state = I2C_STOP;
}
static inline void i2c_prepare_data_xmit_recv() {
if(i2c_sequence_length == 0) {
i2c_prepare_stop(); // nothing more to do, prepare to send STOP
} else {
if(*i2c_sequence == I2C_RESTART) {
USICTL0 |= USIOE; // SDA = output
USISRL = 0xff; // prepare and send a dummy bit, so that SDA is high
USICNT = (USICNT & 0xE0) | 1;
i2c_state = I2C_START;
}
else if(*i2c_sequence == I2C_READ) {
USICTL0 &= ~USIOE; // SDA = input
USICNT = (USICNT & 0xE0) | 8; // Bit counter = 8, RX data
i2c_state = I2C_RECEIVED_DATA; // next state: Test data and ACK/NACK
} else { // a write
(*i2c_sequence >> 8) == 0
USICTL0 |= USIOE; // SDA = output
USISRL = (char)(*i2c_sequence); // Load data byte
USICNT = (USICNT & 0xE0) | 8; // Bit counter = 8, start TX
i2c_state = I2C_PREPARE_ACKNACK; // next state: prepare to receive data ACK/NACK
}
i2c_sequence++;
i2c_sequence_length--;
}
}
#ifdef __GNUC__
__attribute__((interrupt(USI_VECTOR)))
#else
#pragma vector = USI_VECTOR
__interrupt
#endif
void USI_TXRX(void)
{
switch(__even_in_range(i2c_state,12)) {
case I2C_IDLE:
break;
case I2C_START: // generate start condition
USISRL = 0x00;
USICTL0 |= (USIGE|USIOE);
USICTL0 &= ~USIGE;
i2c_prepare_data_xmit_recv();
break;
case I2C_PREPARE_ACKNACK: // prepare to receive ACK/NACK
USICTL0 &= ~USIOE; // SDA = input
USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit into USISRL
i2c_state = I2C_HANDLE_RXTX; // Go to next state: check ACK/NACK and
continue xmitting/receiving if necessary
break;
case I2C_HANDLE_RXTX: // Process Address Ack/Nack & handle data TX
if((USISRL & BIT0) != 0) { // did we get a NACK?
i2c_prepare_stop();
} else {
i2c_prepare_data_xmit_recv();
}
break;
case I2C_RECEIVED_DATA: // received data, send ACK/NACK
*i2c_receive_buffer = USISRL;
i2c_receive_buffer++;
USICTL0 |= USIOE; // SDA = output
if(i2c_sequence_length > 0) {
// If this is not the last byte
USISRL = 0x00; // ACK
i2c_state = I2C_HANDLE_RXTX; // Go to next state: data/rcv again
} else { // last byte: send NACK
USISRL = 0xff; // NACK
i2c_state = I2C_PREPARE_STOP; // stop condition is next
}
USICNT |= 0x01; // Bit counter = 1, send ACK/NACK bit
break;
case I2C_PREPARE_STOP: // prepare stop condition
i2c_prepare_stop(); // prepare stop, go to state 14 next
break;
case I2C_STOP: // Generate Stop Condition
USISRL = 0x0FF; // USISRL = 1 to release SDA
USICTL0 |= USIGE; // Transparent latch enabled
USICTL0 &= ~(USIGE|USIOE); // Latch/SDA output disabled
i2c_state = I2C_IDLE; // Reset state machine for next xmt
if(i2c_wakeup_sr_bits) {
_bic_SR_register_on_exit(i2c_wakeup_sr_bits); // exit active if prompted to
}
break;
}
USICTL1 &= ~USIIFG; // Clear pending flag
}
void main(){
i2c_init(USIDIV_5, USISSEL_2);
uint16_t PUP[] = {0xEA, 0x00};
uint16_t PDWN[] = {0xEA, 0x20};
uint16_t CVOL_PowerUp[] = {0xEA, 0xAF, 0x00};
uint16_t AMODE_PowerUp[] = {0xEA, 0x05, 0x45};
uint16_t AMODE_PowerDown[] = {0xEA, 0x05, 0x41};
uint16_t RDSTAT_Command[] = {0xEA, 0xB0};
uint16_t RDSTAT_Read[] = {0xEB, I2C_READ};
uint16_t START[] = {0xEA, 0x51};
uint16_t PLAY[] = {0xEA, 0x40, 0x03};
uint16_t STOP[] = {0xEA, 0x61};
i2c_send_sequence(PUP, 2, &status, LPM0_bits); // 00
i2c_send_sequence(CVOL_PowerUp, 3, &status, LPM0_bits); // AF 00
i2c_send_sequence(AMODE_PowerUp, 3, &status, LPM0_bits); // 05 45
i2c_send_sequence(PLAY, 3, &status, LPM0_bits); // 40 03
i2c_send_sequence(RDSTAT_Command, 2, &status, LPM0_bits); // B0
i2c_send_sequence(RDSTAT_Read, 2, &status, LPM0_bits);
}
void i2c_init(uint16_t usi_clock_divider, uint16_t usi_clock_source) {
_disable_interrupts();
USICTL0 = USIPE6|USIPE7|USIMST|USISWRST; // Port & USI mode setup
USICTL1 = USII2C|USIIE; // Enable I2C mode & USI interrupt
USICKCTL = usi_clock_divider | usi_clock_source | USICKPL;
USICNT |= USIIFGCC; // Disable automatic clear control
USICTL0 &= ~USISWRST; // Enable USI
USICTL1 &= ~USIIFG; // Clear pending flag
_enable_interrupts();
P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0
P1REN |= 0xC0; // P1.6 & P1.7 Pullups
P1DIR = 0xFF; // Unused pins as outputs
P2OUT = 0;
P2DIR = 0xFF;
}
This is code run result gotten by using Beagle(communication data recorder), and I believe you can see command flow is repeating (from 'Write 00' to 'Read EE')
I have no idea why main function repeats without any loop function.
I want this code run main function's command flow only once.
Do you happen to know why this happens and how to resolve this problem? 😥
Thank you!
Sincerely
Noh

Most programs for a microcontroller have some assembly language initialisation code that does some basic configuration of the MCU, copies the data section from flash to RAM, zeros the .bss, then jumps to main().
Typically, main() would never return. It would consist of an infinite loop, doing whatever tasks the software is meant to do, forever, until power is removed.
So your code returning is not very typical. What is the MCU meant to do if main() returns? It has nothing else to run. Some options for it might be to:
Spin doing nothing
Call main() again (in a loop)
Reset the MCU, which effectively restarts your code
It sounds like, in your case, either 2 or 3 is happening.
If you want your code to just stop after it has done its thing, add an empty infinite loop at the end of main():
for (;;)
;

Related

SPI Communication between STM32 and ADXL345

I am trying to use the SPI communication to read data from the ADXL345 accelerometer. I configured the different pins and SPI in master mode, and tried reading the x, y and z axis accelerations.
My issue is that the SPI readings are always 0. I tried debugging to find the issue and I realized that RXNE is never set even though I'm transmitting data and I don't really get why.
I'm using STM32F103 Board.
Here's my code:
#include "Driver_GPIO.h"
#include "stm32f10x.h"
uint8_t RxData[6];
int x,y,z;
float x_acc,y_acc,z_acc;
void GPIO_Config (void)
{
MyGPIO_Struct_TypeDef NSS={GPIOA,4,Out_OD}; // Output Open Drain
MyGPIO_Struct_TypeDef SCK={GPIOA,5,AltOut_Ppull}; // Alternate Output Push-Pull
MyGPIO_Struct_TypeDef MISO={GPIOA,6,In_Floating}; // Input Floating
MyGPIO_Struct_TypeDef MOSI={GPIOA,7,AltOut_Ppull}; // Alternate Output Push-Pull
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //enable GPIOA clk
MyGPIO_Init(&NSS);
MyGPIO_Init(&SCK);
MyGPIO_Init(&MISO);
MyGPIO_Init(&MOSI);
}
void SPI_Enable (void)
{
SPI1->CR1 |= (SPI_CR1_SPE); // SPE=1, Peripheral enabled
}
void SPI_Disable (void)
{
SPI1->CR1 &= ~(SPI_CR1_SPE); // SPE=0, Peripheral Disabled
}
void CS_Enable (void)
{
GPIOA->BSRR |= GPIO_BSRR_BR9;
}
void CS_Disable (void)
{
GPIOA->BSRR |= GPIO_BSRR_BS9;
}
void SPI_Config(void){
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // Enable SPI1 CLock
SPI1->CR1 |= SPI_CR1_CPOL| SPI_CR1_CPHA; // CPOL=1, CPHA=1
SPI1->CR1 |= SPI_CR1_MSTR; // Master Mode
SPI1->CR1 |= (SPI_CR1_BR_0)| (SPI_CR1_BR_1); // BR[2:0] = 400: fPCLK/16, PCLK2 = 72MHz, SPI clk = 3.375MHz
SPI1->CR1 &= ~SPI_CR1_LSBFIRST; // LSBFIRST = 0, MSB first
SPI1->CR1 |= (SPI_CR1_SSM) | (SPI_CR1_SSI); // SSM=1, SSI=1 -> Software Slave Management
SPI1->CR1 &= ~SPI_CR1_RXONLY; // RXONLY = 0, full-duplex
SPI1->CR1 &= ~SPI_CR1_DFF; // DFF=0, 8 bit data
SPI1->CR2 = 0;
}
void SPI_Transmission(uint8_t *data, int size){
uint8_t clear;
//check flag TxE //
int i=0;
while (i<size)
{
while (!((SPI1->SR)&(SPI_SR_TXE))){}; // buffer is empty
*(volatile uint8_t *)&SPI1->DR = data[i];
i++;
}
while (!((SPI1->SR)&(SPI_SR_TXE))){}; // buffer is empty
while (((SPI1->SR)&(SPI_SR_BSY))){}; // buffer not communicating
clear= SPI1->DR; // empty Overrun flag
clear= SPI1->SR;
}
void SPI_Receive (uint8_t *data,int size)
{
while (size)
{
while (((SPI1->SR)&(SPI_SR_BSY))) {}; // buffer not communicating
*(volatile uint8_t *)&SPI1->DR = 0; // dummy data
while (!((SPI1->SR) &(SPI_SR_RXNE))){};
// buffer is not empty
*data++= *(volatile uint8_t *)&SPI1->DR;
size--;
}
}
void adxl345_write (uint8_t address, uint8_t value)
{
uint8_t data[2];
data[0] = address|0x40; // multibyte write
data[1] = value;
CS_Enable (); // pull the cs pin low
SPI_Transmission (data,2); // write data to register
CS_Disable (); // pull the cs pin high
}
void adxl345_read (uint8_t address, uint8_t *RxData)
{
address |= 0x80; // read operation
address |= 0x40; // multibyte read
CS_Enable (); // pull the pin low
SPI_Transmission (&address,1); // send address
SPI_Receive (RxData,6); // receive 6 bytes data
CS_Disable ();; // pull the pin high
}
void adxl345_init (void)
{
adxl345_write (0x31, 0x01); // data_format range= +- 4g
adxl345_write (0x2d, 0x00); // reset all bits
adxl345_write (0x2d, 0x08); // power_cntl measure and wake up 8hz
}
int main(void)
{
GPIO_Config();
SPI_Config();
SPI_Enable();
adxl345_init();
do{
adxl345_read(0x32,RxData);
x = ((RxData[1]<<8)|RxData[0]); // DATA X0, X1
y = ((RxData[3]<<8)|RxData[2]); // DATA Y0, Y1
z = ((RxData[5]<<8)|RxData[4]); // DATA Z0, Z1
// Scale Factor for Xout, Yout and Zout is 7.8 mg/LSB for a +-4g, 10-bit resolution
// ==> multiply by 0.0078 to get real acceleration values
x_acc= x * 0.0078;
y_acc= y * 0.0078;
z_acc= z * 0.0078;
}while(1);
}
As already stated you have a lot of issues here
Why NSS pin is configured open-drain? Typically CS lines are push-pull. I don't know the schematics, but this is the first time I see an open-drain CS
In GPIO_Config NSS is pin 4, yet pin 9 is toggled from CS_Enable
If F1 series there is separate clocking bit for the alternate functions, it's not enabled
It is also weird that you are telling that RXNE is always zero and the readings returns zero. Your code should stuck in while loops if RXNE stays zero
I will not analyze magic numbers as I do not have time check every number in the RM. But you have many obvious issues.
Deley or readback is required after enabling the peripheral clock. You instantly set the registers which is wrong. Add __DSB(); or readback (for example (void)RCC->APB2ENR;). Same for all peripherals

Serial Connection ATMEGA328p

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 */
}

SPI with Atmega32 and At42QT2100

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!

EFM32 Giant Gecko, Interrupt procedure not working

I am using a EFM32 Giant Gecko 3700 starter kit for basic UART echoing.
When i echo RX to TX in a while(1) loop in my main function it works. However when i want to use the interrupt function, it no longer works. Checking the registers shows that my data is being read correctly, it just does not send it back.
My code:
#include "efm32gg990f1024.h"
#include "em_chip.h" // required for CHIP_Init() function
#include <string.h>
#define COM_PORT 3 // gpioPortD (USART location #1: PD0 and PD1)
#define UART_TX_pin 0
char rx_char = 0; // Temp variable for storing received characters
int main() {
CHIP_Init(); // This function addresses some chip errata and should be called at the start of every EFM32 application (need em_system.c)
uint8_t i;
char test_string[] = "\n\rHello World!\n\r";
CMU->CTRL |= (1 << 14); // Set HF clock divider to /2 to keep core frequency <32MHz
CMU->OSCENCMD |= 0x4; // Enable XTAL Oscillator
while(! (CMU->STATUS & 0x8) ); // Wait for XTAL osc to stabilize
CMU->CMD = 0x2; // Select HF XTAL osc as system clock source. 48MHz XTAL, but we divided the system clock by 2, therefore our HF clock should be 24MHz
CMU->HFPERCLKEN0 = (1 << 13) | (1 << 1); // Enable GPIO, and USART1 peripheral clocks
GPIO->P[COM_PORT].MODEL = (1 << 4) | (4 << 0); // Configure PD0 as digital output and PD1 as input
GPIO->P[COM_PORT].DOUTSET = (1 << UART_TX_pin); // Initialize PD0 high since UART TX idles high (otherwise glitches can occur)
// Use default value for USART1->CTRL: asynch mode, x16 OVS, lsb first, CLK idle low
// Default frame options: 8-none-1-none
USART1->CLKDIV = (48 << 6); // 48 will give 115200 baud rate (using 16-bit oversampling with 24MHz peripheral clock)
USART1->CMD = (1 << 11) | (1 << 10) | (1 << 2) | (1 << 0); // Clear RX/TX buffers and shif regs, Enable Transmitter and Receiver
USART1->IFC = 0x1FF9; // clear all USART interrupt flags
USART1->ROUTE = 0x103; // Enable TX and RX pins, use location #1 (UART TX and RX located at PD0 and PD1, see EFM32GG990 datasheet for details)
// Print test string
for(i=0; i<strlen(test_string); i++) {
while( !(USART1->STATUS & (1 << 6)) ); // wait for TX buffer to empty
USART1->TXDATA = test_string[i]; // print each character of the test string
}
while(1) {
// what used to be in main loop
/*
if(USART1->STATUS & (1 << 7)) { // if RX buffer contains valid data
rx_char = USART1->RXDATA; // store the data
}
if(rx_char) { // if we have a valid character
if(USART1->STATUS & (1 << 6)) { // check if TX buffer is empty
USART1->TXDATA = rx_char; // echo received char
rx_char = 0; // reset temp variable
}
}
*/
}
}
void USART1_RX_IRQHandler(void)
{
if(USART1->STATUS & (1 << 7)) { // if RX buffer contains valid data
rx_char = USART1->RXDATA; // store the data
}
if(rx_char) { // if we have a valid character
if(USART1->STATUS & (1 << 6)) { // check if TX buffer is empty
USART1->TXDATA = rx_char; // echo received char
rx_char = 0; // reset temp variable
}
}
}
You forgot to enable the interrupt vector in the NVIC, and also in the USART.
USART1->IEN = USART_IEN_RXDATAV;
NVIC_EnableIRQ(USART1_RX_IRQn);

Where have the missing letters gone?

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.

Resources