EFM32 Giant Gecko, Interrupt procedure not working - c

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);

Related

Am I setting I2C CCR and TRISE wrong? STM32 [bare-metal]

Following #wovano's suggestion, I'll be boiling down the question. For the old versions of the question, see the editing history.
Overview
I'm trying to include I2C on my project (STM32F407ZGT6, MMA8452Q accelerometer) and I'm setting everything bare-metal. I'm using gschorcht library for the accelerometer functions. I currently do not have access to an osciloscope nor to an FT232H.
Problem
I am unsure if my I2C is working properly: when I try to read my Device ID, I get 0x22 instead of 0x2A*. I'm also not being able to read data in a loop. If I use if (mma845x_new_data (sensor) && mma845x_get_float_data (sensor, &data)), I never get a positive condition, and adjusting as below forces me into the Default_Handler: Infinite_Loop for debugging:
void read_data(void)
{
mma845x_float_data_t data;
if (mma845x_new_data (sensor))
{
if(mma845x_get_float_data (sensor, &data))
{
// max. full scale is +-16 g and best resolution is 1 mg, i.e. 5 digits
printf("[MMA845X (xyz)[g]] ax=%+7.3f ay=%+7.3f az=%+7.3f\n", data.ax, data.ay, data.az);
return;
}
}
printf("[not new MMA845X (xyz)[g]] ax=%+7.3f ay=%+7.3f az=%+7.3f\n", data.ax, data.ay, data.az);
}
The Debug tab shows this trace/breakpoint trap thread:
I'm wondering if I did something wrong with my CCR or TRISE setting (I included below the calculations I'm using). I have my SYSCLK at 168MHz and APB1 at 42MHz (APB1PRESC = 4), and I'm currently testing the Standard Mode.
Things I have right
the board has all pull-up resistors properly placed
MODER and AFR are properly set
the SA0 is set to high- or low-logical level to match the device address
STOP is being sent after reading data from DR
Code
void init_gpio(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; //Port B
GPIOB->MODER |= (2U << 12U); //MMA845_SCL || PB6
GPIOB->AFR[0] |= (4U << 24U); //AF4
GPIOB->OTYPER |= (1U << 6U); //Output Type to Open Drain
GPIOB->PUPDR |= (1U << 12U); //Set to Pull-Up
GPIOB->MODER |= (2U << 14U); //MMA845_SDA || PB7
GPIOB->AFR[0] |= (4U << 28U); //AF4
GPIOB->OTYPER |= (1U << 7U); //Output Type to Open Drain
GPIOB->PUPDR |= (1U << 14U); //Set to Pull-Up
}
/*i2c_init*/
void i2c_init(I2C_TypeDef *I2Cx)
{
/*Enable clock access to I2Cs*/
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; //enable I2C1
// RCC->APB1ENR |= RCC_APB1ENR_I2C2EN; //enable I2C2
// RCC->APB1ENR |= RCC_APB1ENR_I2C3EN; //enable I2C3
RCC->APB1ENR;
/*Reset I2C*/
I2Cx->CR1 |= I2C_CR1_SWRST; /*!BUSY ON */
I2Cx->CR1 &= ~I2C_CR1_SWRST; /*!BUSY OFF*/
int CCR_VAL;
int TRISE_VAL;
int MAX_FRQ;
/*Set I2C frequency same as APB*/
MAX_FRQ = (SYSCLK/APB1PRESC)/1000000; //= 42 # max clock speed
I2Cx->CR2 &= ~msk(6,0); /*!BUSY ON*/
I2Cx->CR2 |= MAX_FRQ;
if(!MASTER_MODE){
/* Standard Mode = 100kb/s*/
/* CCR calculated by half-period of 100k
* divided by the period of the PCLK
* CCR = ((1/100'000)/2)/(1/42'000'000)
* CCR = 5000ns/~24ns = 210
*/
CCR_VAL = 210;
/* TRISE calculated by PCLK (in MHz) + 1
* TRISE = ((42'000'000/1'000'000) + 1)
* TRISE = 42 + 1 = 43
*/
TRISE_VAL = 43;
}
else
{
/*Fast Mode = 400kb/s*/
if(DUTY_MODE)
{
/*16:9 ratio*/
/* CCR calculated by half-period of 100k
* divided by the sum of the duty ratios
* divided by the period of the PCLK
* t_high = 9 * CCR * TPCLK
* t_low = 16 * CCR * TPCLK
* t_high + t_low = 25 * CCR * TPCLK
* CCR = ((1/400'000)/2) / (25/42'000'000)
* CCR = 1250ns/~595ns = 2.1 ~ 2
*/
CCR_VAL = 2;
}
else
{
//2:1 ratio
/* CCR calculated by half-period of 100k
* divided by the sum of the duty ratios
* divided by the period of the PCLK
* t_high = CCR * TPCLK
* t_low = 2 * CCR * TPCLK
* t_high + t_low = 3 * CCR * TPCLK
* CCR = ((1/400'000)/2) / (3/42'000'000)
* CCR = 1250ns/~71ns = 17.5 ~ 17
*/
CCR_VAL = 17;
}
/* TRISE calculated by PCLK (in MHz) * 0.3ms + 1
* TRISE = ((42'000'000/1'000'000)*(300/1000) + 1)
* TRISE = 42 * 0.3 + 1 = 13.6 ~ 14
*/
TRISE_VAL = 14;
}
/*Set Clock Control value*/
I2Cx->CCR |= CCR_VAL; //assuming APB1 = 42MHz, SM = True
I2Cx->CCR |= (set(DUTY_MODE,I2C_CCR_DUTY_Pos) | set(MASTER_MODE,I2C_CCR_FS_Pos));
I2Cx->TRISE |= TRISE_VAL; //assuming APB1 = 42MHz, SM = True
/*Enable I2C*/
I2Cx->CR1 |= I2C_CR1_PE;
}
void set_addr(I2C_TypeDef *I2Cx, uint8_t sAddr, const uint8_t *mAddr, int read)
{
volatile int temp;
/*Check I2C is not busy*/
while(I2Cx->SR2 & I2C_SR2_BUSY);
/*(1) Generate a START, wait for start flag*/
I2Cx->CR1 |= I2C_CR1_START;
while (!(I2Cx->SR1 & I2C_SR1_SB));
/*Transmit slave address + 'write'*/
I2Cx->DR = sAddr << 1;
/*Wait for the address flag*/
while (!(I2Cx->SR1 & I2C_SR1_ADDR));
temp = I2Cx->SR2; //Clear address flag
/*Send memory address*/
//Make sure TXE is emtpy
while (!(I2Cx->SR1 & I2C_SR1_TXE));
I2Cx->DR = mAddr;
//Wait until transmitter is emtpy
while (!(I2Cx->SR1 & I2C_SR1_TXE));
if(read)
{
/*(2) Generate a START, wait for start flag*/
I2Cx->CR1 |= I2C_CR1_START;
while (!(I2Cx->SR1 & I2C_SR1_SB));
/*Transmit slave address + 'read'*/
I2Cx->DR = (sAddr << 1) | 1;
/*Wait for the address flag*/
while (!(I2Cx->SR1 & I2C_SR1_ADDR));
temp = I2Cx->SR2; //Clear address flag
}
}
int i2c_burst_read(I2C_TypeDef *I2Cx, uint8_t sAddr, const uint8_t *mAddr, uint8_t *string, uint32_t size)
{
if(size == 0)
{
return 0;
}
uint8_t *pData = string; //points at the first byte (char) of string
set_addr(I2Cx, sAddr, mAddr, 1);
/*Enable ACK*/
I2Cx->CR1 |= I2C_CR1_ACK;
while(size > 0U)
{
if(size-- == 1)
{
/*Disable ACK*/
I2Cx->CR1 &= ~I2C_CR1_ACK;
/*Wait until the receive flag is set*/
while(!(I2Cx->SR1 & I2C_SR1_RXNE));
//"Generate STOP" was here before
/*Read data from the DR*/
*pData++ = I2Cx->DR;
break;
}
else
{
/*Wait until the receive flag is set*/
while(!(I2Cx->SR1 & I2C_SR1_RXNE));
/*Read data from the DR*/
*pData++ = I2Cx->DR;
}
}
/*Generate a STOP after receiving*/
I2Cx->CR1 |= I2C_CR1_STOP;
return 1;
}
int i2c_burst_write(I2C_TypeDef *I2Cx, uint8_t sAddr, const uint8_t *mAddr, uint8_t *string, uint32_t size)
{
uint8_t *pData = string; //points at the first byte (char) of string
set_addr(I2Cx, sAddr, mAddr, 0);
while(size > 0U)
{
/*Wait for transmitter to be empty*/
while(!(I2Cx->SR1 & I2C_SR1_TXE));
I2Cx->DR = *pData++;
size--;
}
/*Wait for byte transfer finished flag*/
while(!(I2Cx->SR1 & I2C_SR1_BTF));
/*Generate a STOP after writing*/
I2Cx->CR1 |= I2C_CR1_STOP;
return 1;
}
*This might be due to it being a "different brand". Although it raises some suspicion that it isn't reading all the bits (0x2A in binary is 0b0010 1010 and 0x22 is 0b0010 0010), testing it with another accelerometer gives me the value of 0x05. There's a chance bits are being lost but I'm not sure.
I figured my I2C communication was actually working! So the answer is 'Yes, my CCR and TRISE' settings were correct (at least for the 100kHz mode). To check this, I borrowed an Arduino and I pastade a simple Wire code to read and write from the line. With it, I discovered that:
I could read and write to the I2C bus (without register address)
I had problems when using the register address mAddr
The chip's ID is actually 0x2A
I was mistakenly sending to the function the address of the variable containing the memory address instead of its content (instead of mAddr = 0x1D, I was passing &mAddr as argument).
Also, #wovano guess about the HardFault was correct too. The printf was causing the crash, either because of the floating-point linkage or because it was reading an empty variable (since it wasn't getting any data).
I'm still having issues reading data from the MMA since my STATUS->ZYXDR flag never goes high (mma845x_new_data(sensor) always returns 0). My initialization is as follows, in case anyone has experience with Freescale semiconductors (library link):
#include "mma845x.h"
#define MMA845X_I2C_ADDRESS_1 0x1c // SDO pin is low
#define MMA845X_I2C_ADDRESS_2 0x1d // SDO pin is high
static mma845x_sensor_t* sensor;
void init_MMA_sensor(void)
{
sensor = mma845x_init_sensor(I2C1, MMA845X_I2C_ADDRESS_2);
mma845x_config_int_signals(sensor, mma845x_high_active, mma845x_push_pull);
mma845x_config_hpf(sensor, 0, true);
mma845x_set_scale(sensor, mma845x_scale_2_g);
mma845x_set_mode(sensor, mma845x_high_res, mma845x_odr_50, true, false); //make it active!
}
void read_data(void)
{
mma845x_float_data_t data;
if (mma845x_new_data(sensor))
{
if(mma845x_get_float_data(sensor, &data))
{
// max. full scale is +-16 g and best resolution is 1 mg, i.e. 5 digits
printf("[MMA845X (xyz)[g]] ax=%+7.3f ay=%+7.3f az=%+7.3f\r\n",
data.ax, data.ay, data.az);
return;
}
}
printf("No new data available\r\n");
}
int main(void)
{
/*Setup*/
clock_init_168();
init_systick_MS(SYSTICK_LOAD_VAL_MS);
gpio_init();
uart_init();
i2c_init(I2C1);
init_MMA_sensor();
for(;;)
{
read_data();
delayMS(500);
}
}
But the intial question is resolved. Thanks for all your insight.

STM32 & TLV5628 SPI Communication

Hi Everyone and thank you for your time.
I have been working on interfacing the STM32f446RE Nucleo board with the TLV5628 8 Bit Octal Serial DAC. I have ran into multiple issues, but the current issue has been one of two things:
1) The data and clock lines showing the exact same information
or
2) The data line showing information, but nothing on the clock line.
Regardless, the information coming out is completely incorrect.
Here is my setup code:
void SPI_INIT(void){
// Enable clocks for C
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
// SPI GPIO
GPIOC->MODER |= 2 << 3*2; // PC3 data pin
GPIOC->MODER |= 2 << 7*2; // PC7 clock pin
GPIOC->MODER |= 1 << 2*2; //pc2 load
GPIOC->MODER |= 1 << 4*2; //pc4 ldac - probably set low permanently
// Pins default to push-pull
// set all to high speed
GPIOC->OSPEEDR |= (3 << 2*2) | (3 << 3*2) | (3 << 4*2) | (3 << 7*2);
GPIOC->AFR[0] |= 5<< 6*2; // Alt func 5 pc3 - SPI2
GPIOC->AFR[0] |= 5 << 7*2; // Alt func 5 pc7 - SPI2
// SPI Setup
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN; // Enable SPI Clock
RCC->APB1RSTR |= RCC_APB1RSTR_SPI2RST; // reset SPI2
RCC->APB1RSTR &= ~RCC_APB1RSTR_SPI2RST;// clear the reset
// Control Register 1
SPI2->CR1 &= ~SPI_CR1_SPE; // Disable SPI
SPI2->CR1 |= SPI_CR1_MSTR; // master mode
SPI2->CR1 &= ~SPI_CR1_RXONLY; // transmit, 0 == full duplex
SPI2->CR1 &= ~SPI_CR1_DFF; // 8 bit format
SPI2->CR1 &= ~SPI_CR1_LSBFIRST; // MSB first
SPI2->CR1 &= ~SPI_CR1_CPOL;// low polarity, so 0 when idle
SPI2->CR1 |= 4 << 3; // (180M/4)/32 = 1.41 MHz
SPI2->CR1 |= SPI_CR1_CPHA; // first edge, look in data sheet
//Questionable settings
// Biderectional data line
SPI2->CR1 |= SPI_CR1_BIDIMODE; // 1/17/2019 --> Check to see if this fixes something
SPI2->CR1 |= SPI_CR1_BIDIOE; // idk if i need this
// CRC Polynomial Register
SPI2->CRCPR = 10;
// Control Register 2
SPI2->CR2 |= 1<<2; // SS output enabled
SPI2->CR1 |= SPI_CR1_SPE; // enable, has to be last
}
And here is my SPI Write code:
void SPI_Write(int dacSelect, int adcData){
while((SPI2->SR & SPI_SR_TXE) != 0);
GPIOC->ODR |= 1 << 2; // load set high to read data
SPI2->DR = dacArray[dacSelect]; // send address
SPI2->DR = adcData; // send adc data
while((SPI2->SR & SPI_SR_BSY) == SPI_SR_BSY);
GPIOC->ODR &= ~(1 << 2); // Send load low to load data
Delay(10); // short delay
GPIOC->ODR |= 1 << 2;
}
You can use STMCubeMX to generate codes for STM microprocessors and boards. Following code blocks are generated from STM32ubeMX for STM32F4. You should change baudrate for your sensor.
SPI_HandleTypeDef hspi;
SPI_HandleTypeDef SpiHandle;
void Spi_Initialize(void)
{
/*##-1- Configure the SPI peripheral #######################################*/
/* Set the SPI parameters */
SpiHandle.Instance = SPI2;
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SpiHandle.Init.CRCPolynomial = 7;
SpiHandle.Init.NSS = SPI_NSS_SOFT;
SpiHandle.Init.Mode = SPI_MODE_MASTER;
if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
{
while(1){};
}
}
void Spi_Read(void )
{
uint8_t SpiData[2];
uint8_t tempmessage = 8;
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,RESET); // CS pin
HAL_SPI_TransmitReceive(&hspi,&tempmessage,SpiData,2,5000); // Read Data
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,SET); // CS Pin
}
void Spi_Write(uint8_t *Data, uint8_t size)
{
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,RESET); // CS pin
HAL_SPI_Transmit(&hspi, Data, size, 5000); // Write Data
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,SET); // CS Pin
}

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!

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