How does this flush USART c code work? - usart

So I have old code I am looking at, that I am supposed to update for a new micro controller. In the old code there is a function to flush the USART in case there is junk on it from the start up. The code is bellow:
#define RXC 7
#define RX_COMPLETE (1<<RXC)
void UART1_FLUSH(void){
unsigned char dummy;
while ( UCSR1A & RX_COMPLETE ) dummy = UDR1;
}
Now from what I understand the while loop will keep going as long as there is something to read from the USART from register UDR1 that is why it is being stored in dummy since we do not need it. Now what I need help being explained to me is why the while loop works the way that it does?

Looking for UCSRnA in http://upcommons.upc.edu/pfc/bitstream/2099.1/10997/4/Annex3.pdf that code simply waits until bit 7 ("RXCn: USART Receive Complete") in USCR1A is off.
That document says about bit 7 This flag bit is set when there are unread data in the receive buffer and cleared when the receive buffer is empty.
(1<<RXC) is the numerical value of bit 7. A bitwise AND (the &) between it and the value read from UCSR1A results in 0 (if the bit is off) or (1<<RXC) (if the bit is on). Since (1<<7) is 128 and that is not zero, the loop will be entered when the bit is set.

Related

What does UART_RX returns

I'm using an efm32lg230f256 microcontroller and in its code there is a line which uses USART_Rx and it returns:
1 2 3 4
but when I look inside of it I can't see how it retuns 1 2 3 4. I tried to look in the data sheet but there are no such names.
What is the logic in this function? And why does it do this?
c = USART_Rx(uart);
uint8_t USART_Rx(USART_TypeDef *usart)
{
while (!(usart->STATUS & USART_STATUS_RXDATAV))
;
return (uint8_t)usart->RXDATA;
}
"1 2 3 4" is simply the device password
This is a HAL (Hardware Abstraction Layer).
It is probably defined something like this:
typedef struct {
//other uart registers
uint8_t STATUS
//other uart registers
uint8_t RXDATA
} USART_TypeDef;
#define USART_STATUS_RXDATAV 0b00001000 // or equivalent hex value
This struct is a way of interfacing with the memory mapped to the USART peripheral. As such the USART_TypeDef *usart pointer points to a piece of memory which is the location of an USART. When it reads usart->STATUS, it reads the data in the location pointed to by usart, which is the usart STATUS register.
The USART_STATUS_RXDATAV is a bitmask, this is used to extract only the value of RXDATAV which stands for RX DATa AVailable. As such the operation usart->STATUS & USART_STATUS_RXDATAV will return a true value only if the bit at position USART_STATUS_RXDATAV is 1. Otherwise this is false. (True and false are 1 and 0 in C generally.)
(uint8_t)usart->RXDATA
Is reading the data in the RXDATA register of that uart. As such it reads the currently received value.
To insure that RXDATA contains usefull new data,
while (!(usart->STATUS & USART_STATUS_RXDATAV))
;
is executed. This waits for the UART to have received data available.
The datasheet is often quite useful but if more detailed information is needed then the reference manual is the next step. Page 447 is the one about the USART. Page 474 shows the memory layout of the USART peripheral.

AVR Internal eeprom reading issue

I am using the internal EEPROM of atmega8A using avr's EEPROM library. My code looks like this
#define EEPROM_ADDR 0x0A
int main(void)
{
_delay_ms(2000);
LED_Initialize();
vBlink_Led(100, 2);
//eeprom_write_byte((uint8_t*)EEPROM_ADDR, 8);
val = eeprom_read_byte((uint8_t*)EEPROM_ADDR);
while (1);
}
when i uncomment the line eeprom_write_byte((uint8_t*)EEPROM_ADDR, 8); and then read using val = eeprom_read_byte((uint8_t*)EEPROM_ADDR);, the correct value 8 is read. But when I comment on the line and then reflash the code, the values changes to 255.
any suggestions?
note - i have unchecked the box in avrdudes for erase flash and eeprom
Normaly, when "Chip Erase" operation is performed, the EEPROM is being cleared as well.
To prevent this, you have to program (i.e. set to zero) EESAVE fuse bit, which is 3rd bit in the high fuse byte (please refer to the datasheet chapter 29.2 Fuse Bits)

Reading values of SPI data register of STM32 MCU

There are quite a few similar questions, but none seem to have quite the same issue. I am connecting an STML4 MCU to a 6-axis sensor (LSM6DS3). I have successfully implemented everything in I2C, but would like the extra speed of SPI (and DMA, if I can get these first steps working...). So for a first step, I am trying to read the WHO_AM_I register (0x0F) of the device, which should reply with 0x69. Here is the code:
uint8_t who = 0;
// Sanity check/debugging aid should get 0x5D
who = 0x43 + 0x1A;
// Set SS low
GPIO_WritePin (GPIOB, LL_GPIO_PIN_7, GPIO_PIN_RESET);
// while tx buffer is in use, wait
while (!LL_SPI_IsActiveFlag_TXE(SPI1));
// Send READ command to the WHO_AM_I register
(SPI1->DR) = 0x8F;
// while rx buffer is in use, wait
while (!LL_SPI_IsActiveFlag_RXNE(SPI1));
// Get data off the register
who = (SPI1->DR);
// Wait for everything to wrap up before setting SS high again
while (LL_SPI_IsActiveFlag_BSY(SPI1));
// OK, now we can set SS high
GPIO_WritePin (GPIOB, LL_GPIO_PIN_7, GPIO_PIN_SET);
On the scope/analyzer, I see everything run as expected, including the sensor sending back 0x69. However, when I set a break on the other side of this code block, I see that who goes from 0 to 0x5D to 0xFF. It never reads the 0x69. I looked through other code examples and some people have a second transmit with the data set to some dummy value (usually 0xFF or 0x0), so I also tried that, but the sensor seems to get confused during the second attempt and who ends up being 0x48. I have tried every permutation of waiting for the RXNE/TXE/BSY flags that I could have, as well as many many other things to get the variable to correctly read the SPI1 data register, including reading other registers off the sensor, but all to no avail.
So then the question is, how does one correctly read values off this register?
I should also mention that I can successfully write to the device's registers. I can send the command I want, then read it back and see that it worked on the scope, even though I can never get the values assigned to a variable in code. I always get 0xFF.
I include a screen of my analyzer showing the sensor sending back 0x69 from a single read request, as well as the garbled mess it sends if I try the "dummy transmit" method.
SPI always (if the receiver is enabled) receives the data when you transfer.
This is the problem with the libraries that you do not know what is there. SPI is a lot easier to program using registers.
I assume that your data is 8bits.
You need to set the 1/4 (one byte) FIFO threshold during the SPI initialization by:
SPI1 -> CR2 |= SPI_CR2_FRXTH;
next you need to read the data from the FIFO after every write (you need also to force the compiler to use the correct size (in this case 8bits) load and store instructions):
*(volatile uint8_t *)&SPI1->DR = 0x8F; // write exactly 8 bits to the FIFO
while (!LL_SPI_IsActiveFlag_RXNE(SPI1));
dummy = *(volatile uint8_t *)&SPI-> DR;
*(volatile uint8_t *)&SPI1->DR = 0; // dummy write
while (!LL_SPI_IsActiveFlag_RXNE(SPI1));
who = *(volatile uint8_t *)&(SPI1->DR);
I do not know what is the point of using the LL libraries.
instead of
while (!LL_SPI_IsActiveFlag_RXNE(SPI1));
use registers
while (!(SPI1 -> SR & SPI_SR_RNE));
You can also wrap it into the function:
uint8_t SPI_ReadWrite8(SPI_TypeDef *spi, uint8_t data)
{
while(!(spi -> SR & SPI_SR_TXE));
*(volatile uint8_t *)&spi->DR = data;
while (!(spi -> SR & SPI_SR_RNE));
return *(volatile uint8_t *)&spi-> DR;
}
And
SPI_ReadWrite8(SPI1, 0x8f);
who = SPI_ReadWrite8(SPI1, 0);

Bit banging for SPI in ARM

I am trying to read the data from FXLS8471Q 3-Axis, Linear Accelerometer using SPI. I am using bit banging method to read the data from Accelerometer. I am using LPC 2184 ARM processor. I used the following code.
unsigned char spiReadReg (const unsigned char regAddr)
{
unsigned char SPICount;
unsigned char SPIData;
SPI_CS = 1;
SPI_CK = 0;
SPIData = regAddr;
SPI_CS = 0;
for (SPICount = 0; SPICount < 8; SPICount++)
{
if (SPIData & 0x80)
SPI_MOSI = 1;
else
SPI_MOSI = 0;
SPI_CK = 1;
SPI_CK = 0;
SPIData <<= 1;
}
SPI_MOSI = 0;
SPIData = 0;
for (SPICount = 0; SPICount < 8; SPICount++)
{
SPIData <<=1;
SPI_CK = 1;
SPIData += SPI_MISO;
SPI_CK = 0;
SPIData &=(0xFE);
}
SPI_CS = 1;
return ((unsigned char)SPIData);
}
But instead of getting valid value 0x6A , I am getting garbage value.
Please help me out to solve this problem;
SPIData &=(0xFE); as pointed out in another answer, is definitely wrong as it erases the bit you just received.
However, there are other major issues with your code.
An SPI slave device sends you data by setting the value of MISO on a rising or falling clock, depending on the type of device. However, you didn't wait in your code for the value to appear on MISO.
You control the communication by setting the clock to 1 and 0. The datasheet of the accelerometer says on page 19, that
Data is sampled during the rising edge of SCLK and set up during the falling edge of SCLK.
This means that in order to read from it, your processor needs to change the clock from one to zero, thereby signaling the accelerometer to send the next bit to the MISO. This means you did the reverse, you in your code read on a rising edge while you should be reading on the falling edge. After setting the clock to zero, you have to wait a little while until the value appears on MISO, and only then should you read it and add it to your SPIData variable. Table 9, SPI timing indicates how much you have to wait: at least 500 nanoseconds. That's not much, but if your CPU runs faster than 2 MHz then if you don't use a delay, you will try to read the MISO before the accelerometer had time to properly set it.
You also forgot the slave Select, which is actually required to indicate the beginning and the end of a datagram.
Check the Figure 7. SPI Timing Diagram in the datasheet, it indicates what you are required to do and in what order, to communicate with the device using SPI.
I also suggest reading about how the rotating registers of the SPI work, because it seems from its datasheet, that the accelerometer needs to receive a well specified number of bits before useful data appears on its output. Don't forget, as you send a single bit to the device, it also has to send a bit back to you, so if it didn't decode a command yet, it can only send gibberish. Your code, as the master, can only "push" bits in, and collect the bits which "pop out" on the other side. This means you have to send a command, and then send further bits until all the answer is pushed out to you bit by bit.
If you get stuck, I think you will have much more luck getting help on https://electronics.stackexchange.com/, but instead of just putting this same code there (which seems to be blindly copied from www.maximintegrated.com and has absolutely nothing to do with the problem you try to solve), I strongly recommend trying to understand the "Figure 7. SPI Timing Diagram" I was suggesting before, and alter your code accordingly.
Without understanding how the device you try to communicate with works, you will never succeed if you just blindly copy the code from a completely different project just because it says "spi" in the title.
SPIData &=(0xFE);
The above line is causing the problem. Here the LSB is reset to 0 (which contained the data bit just taken from MISO) -- basically you are destroying the bit you just read. Omitting the line should correct the problem.
be sure to compile your function with NO optimization
as that will corrupt the bitbang operation.
this is the code from the maxum site for the spiReadReg function.
(which looks like were you got your code.
However, this is just a guide for the 'general' sequence of operations for communicating with the maxim 1481 part.
the accel. part needs several setup commands and reads completely differently
Suggest reading the app notes and white papers available at freescale.com for the specific part number.
Those app notes/white papers will indicate the sequence of commands needed for setting up a specific mode of operation and how to request/interpret the resulting data.
There are a number of device specifics that your code has not taken into account.
Per the spec sheet the first bit transmitted is a read/write indicator, followed by 8 bits of register address, followed by 7 trash bits (suggest sending all 0's for the trash bits.) followed by the data bits.
Depending on the setup commands, those data bits could be 8 bits or 14 bits or multiple registers of 8 or 14 bits per register.

How to get value from 15th pin of 32bit port in ARM?

I am using an IC, DS1620 to read 1 bit serial data coming on a single line. I need to read this data using one of the ports of ARM microcontroller (LPC2378). ARM ports are 32 bit. How do I get this value into a 1 bit variable?
Edit: In other words I need direct reference to a port pin.
there are no 1 bit variables, but you could isolate a particular bit for example:
uint32_t original_value = whatever();
uint32_t bit15 = (original_value >> 15) & 1; /*bit15 now contains either a 1 or a 0 representing the 15th bit */
Note: I don't know if you were counting bit numbers starting at 0 or 1, so the >> 15 may be off by one, but you get the idea.
The other option is to use bit fields, but that gets messy and IMO is not worth it unless every bit in the value is useful in some way. If you just want one or two bits, shifting and masking is the way to go.
Overall, this article may be of use to you.
For your CPU the answer from Evan Teran should be used. I just wanted to mention the bit-band feature of some other ARM CPU's like the Cortex-M3. For some region of RAM/Peripherals all bits are mapped to a separate address for easy access.
See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337e/Behcjiic.html for more information.
It's simple if you can access the port register directly (I don't have any experience with ARM), just bitwise AND it with the binary mask that corresponds to the bit you want:
var = (PORT_REGISTER & 0x00008000);
Now var contains either 0 if the 15th bit is '0' or 0x00008000 if the 15th bit is '1'.
Also, you can shift it if you want to have either '0' or '1':
var = ((PORT_REGISTER & 0x00008000) >> 15);
The header file(s) which come with your compiler will contains declarations for all of the microcontroller's registers, and the bits in those registers.
In this specific article, let's pretend that the port input register is called PORTA, and the bit you want has a mask defined for it called PORTA15.
Then to read the state of that pin:
PinIsSet = (PORTA & PORTA15) == PORTA15;
Or equivalently, using the ternary operator:
PinIsSet = (PORTA & PORTA15) ? 1 : 0;
As a general point, refer to the reference manual for what all the registers and bits do. Also, look at some examples. (This page on the Keil website contains both, and there are plenty of other examples on the web.)
In LPC2378 ( as the other LPC2xxxx microcontroller family ), I/O ports are in system memory, so you need to declare some variables like this:
#define DALLAS_PIN (*(volatile unsigned long int *)(0xE0028000)) /* Port 0 data register */
#define DALLAS_DDR (*(volatile unsigned long int *)(0xE0028008)) /* Port 0 data direction reg */
#define DALLAS_PIN (1<<15)
Please note that 0xE0028000 is the address for the data register of port0, and 0xE0028008 is the data direction register address for port0. You need to modify this according to the port and bit used in your app.
After that, in your code function, the code or macros for write 1, write 0 and read must be something like this:
#define set_dqout() (DALLAS_DDR&=~DALLAS_PIN) /* Let the pull-up force one, putting I/O pin in input mode */
#define reset_dqout() (DALLAS_DDR|=DALLAS_PIN,DALLAS_PORT&=~DALLAS_PIN) /* force zero putting the I/O in output mode and writing zero on it */
#define read_dqin() (DALLAS_DDR&=~DALLAS_PIN,((DALLAS_PORT & DALLAS_PIN)!= 0)) /* put i/o in input mode and test the state of the i/o pin */
I hope this can help.
Regards!
If testing for bits, it is good to keep in mind the operator evaluation order of C, e.g.
if( port & 0x80 && whatever() )
can result in unexpected behaviour, as you just wrote
if( port & (0x80 && whatever()) )
but probably ment
if( (port & 0x80) && whatever() )

Resources