typecasting char variable into unsigned int - c

I am trying to convert char variables into Unsigned int. my code is
char spi(char data)
{
//Start transmision
SPDR = data;
//Wait for transmision complete
while(!(SPSR & 0x80));
return SPDR;
}
unsigned int ReadAd(void)
{
unsigned int data;
ChipSelectAd(1);
//Read data
CheckStatus();
spi(0x58);
data = (spi(0xFF)<< 8);
data |= spi(0xFF);
return data;
}
Actually my problem is The spi function return an 8bit char so the above code shifts left 8bits the char variable and then assigns it to a 16bit variable, the result will always be 0.
In order to actually shift the data to the left I need to typecast them first to a 16bit type variable. I have tried like this
char spi(char data)
{
//Start transmision
SPDR = data;
//Wait for transmision complete
while(!(SPSR & 0x80));
return SPDR;
}
unsigned int ReadAd(void)
{
unsigned int data;
ChipSelectAd(1);
//Read data
CheckStatus();
spi(0x58);
data = (unsigned int)((unsigned char)spi(0xFF)<< 8);
data |= (unsigned int)((unsigned char)spi(0xFF));
return data;
}
void CheckStatus(void)
{
//char adcStatus;
adcStatus = 0xFF;
//Read status
while(!(adcStatus & 0x80))
{
spi(0x40);
adcStatus = spi(0xFF);
}
}
void ChipSelectAd(char s)
{
if(s == 1){
PORTB.3 = 0; //Switch on ADC
//while(PINB.3); //Wait for chip select pin
}
else
PORTB.3 = 1; //Switch off ADC
}
its not working. please suggest me which function i have to use.
Thanks in advance.

Your problem is not the casts. It works the same without them, due to the integral promotion rules.
#include <stdio.h>
char spi ( char data )
{
char SPDR = data;
return SPDR;
}
unsigned int ReadAd ( void )
{
unsigned int data;
data = spi ( 0x81 ) << 8;
data |= spi ( 0x42 );
return data;
}
int main ( void )
{
printf ( "Result %x\n", ReadAd() );
return 0;
}
This outputs Result ffff8142 on a system where char is a signed type. To get to the real problem, try assinging the values of spi() calls to variables and then print their values. Please also show us the declaration/definition of SPDR.

1) in embedded systems: get rid of the standard integer types, the default char type in particular. If you have a modern compiler, use uint8_t, uint16_t etc from stdint.h. If you have an ancient compiler, then typedef unsigned char uint8_t and so on. If you aren't using unsigned types of known size in embedded systems, you are asking for bugs bugs bugs.
2) Learn and understand integer promotion rules. It is frightening how many programmers there are that don't know about them or understand them.
Once you have the two above fundamentals sorted out, your code should look something like this code:
(I took the liberty to fix various suspicious, possible bugs and the crappy, inconsistent indention. Plus some style nitpicks.)
#include <stdint.h>
uint8_t spi (uint8_t data)
{
SPDR = data; //Start transmision
while((SPSR & 0x80) > 0) //Wait for transmision complete
;
return SPDR;
}
uint16_t ReadAd(void)
{
uint16_t data;
ChipSelectAd(true);
CheckStatus(); //Read data
(void) spi(0x58);
data = ((uint16_t)spi(0xFF)) << 8;
data |= (uint16_t)spi(0xFF);
return data;
}
void CheckStatus(void)
{
uint8_t adcStatus;
do
{
(void) spi(0x40);
adcStatus = spi(0xFF);
} while((adcStatus & 0x80) > 0);
}
void ChipSelectAd(bool on)
{
if(on)
{
PORTB.3 = 0; //Switch on ADC
}
else
{
PORTB.3 = 1; //Switch off ADC
}
}

Related

MPU6050 motion driver library function call cause hardfault exception

Hi I'm try to use mpu6050 on my stm32 project.
I copy the motion driver library from SparkFun_MPU-9250-DMP_Arduino_Library and replace arduino function like arduino_i2c_write to stm32 write function. The replace part work fine. The stm32 board did write bytes into the imu and read from it.
However, when I try to setup the dmp funtion and use the mpu_load_firmware function, I encouter a weird situation.
int mpu_load_firmware(unsigned short length, const unsigned char *firmware,
unsigned short start_addr, unsigned short sample_rate)
{
unsigned short ii;
unsigned short this_write;
/* Must divide evenly into st.hw->bank_size to avoid bank crossings. */
#define LOAD_CHUNK (16)
unsigned char cur[LOAD_CHUNK], tmp[2];
if (st.chip_cfg.dmp_loaded)
/* DMP should only be loaded once. */
return -1;
if (!firmware)
return -1;
for (ii = 0; ii < length; ii += this_write) {
this_write = min(LOAD_CHUNK, length - ii);
if (mpu_write_mem(ii, this_write, (unsigned char*)&(firmware[ii])))
return -1;
if (mpu_read_mem(ii, this_write, cur))
return -1;
if (memcmp(firmware+ii, cur, this_write))
return -2;
}
/* Set program start address. */
tmp[0] = start_addr >> 8;
tmp[1] = start_addr & 0xFF;
if (i2c_write(st.hw->addr, st.reg->prgm_start_h, 2, tmp))
return -1;
st.chip_cfg.dmp_loaded = 1;
st.chip_cfg.dmp_sample_rate = sample_rate;
return 0;
}
When the code run to the line if (mpu_write_mem(ii, this_write, (unsigned char*)&(firmware[ii]))), it cause a hardfault. And I found out that the code cannnot call the mpu_write_mem function porperly. When I start to step in the function, the hardfault exception immediately occurred. I cannot figure it out what cause the exception and how to fix it.
I've checked the pointer, &(firmware[ii]), address, it looks just fine. But the weired thing is that in the mpu_write_mem function, the argument value all differ from the mpu_load_firmware function.(mem_addr != ii, length != this_write, ...) I'm not sure if this cause the exception or the other way around.
Can anyone give me some idea? Thank you very much ~~
Here is the mpu_write_mem function, both function are in the inv_mpu.c file
int mpu_write_mem(unsigned short mem_addr, unsigned short length,
unsigned char *data)
{
unsigned char tmp[2];
if (!data)
return -1;
if (!st.chip_cfg.sensors)
return -1;
tmp[0] = (unsigned char)(mem_addr >> 8);
tmp[1] = (unsigned char)(mem_addr & 0xFF);
/* Check bank boundaries. */
if (tmp[1] + length > st.hw->bank_size)
return -1;
if (i2c_write(st.hw->addr, st.reg->bank_sel, 2, tmp))
return -1;
if (i2c_write(st.hw->addr, st.reg->mem_r_w, length, data))
return -1;
return 0;
}

Can't pass array stored in .h file to C function

I am trying to implement a driver for a sensor(ST-VL53L5CX) on an AVR MCU (AVR128DB48).
The driver comes prewritten, with a few I2C functions for the user to fill in
(So the sensor can be implemented on different platforms).
The driver is made up of multiple c files. API.c, API.h, Buffers.h, Platform.c and Platform.h.
The firmware for the sensor is stored in the Buffers.h file as an array. e.g:
const uint8_t Sensor_Firmware[] = {0x05,...,0x01};
This needs to be written to the sensor.
To do this, I call a function I have written to write multiple bytes to the I2C line:
uint8_t WrMulti(VL53L5CX_Platform *p_platform,uint16_t
RegisterAdress,uint8_t *p_values,uint32_t size)
{
uint8_t count = 0;
uint32_t new_size = size + 2;
//Split Register address into 2 bytes
uint8_t temp0 = (uint8_t)((RegisterAdress & 0xFF00)>> 8);
uint8_t temp1 = (uint8_t)(RegisterAdress & 0x00FF);
//Create new array to hold Register Address and p_values
uint8_t temp_array[new_size] ;
for (int i = 0; i <new_size; i++)
{
temp_array[i] = 0;
}
//Fill temp_array with register address and p_values
temp_array[0] = temp0;
temp_array[1] = temp1;
for (int i = 2; i < (new_size); i++ )
{
temp_array[i] = p_values[count];
count++;
}
//I2C
uint8_t status = 255;
while(!I2C0_Open(p_platform->address)); // sit here until we get the bus..
I2C0_SetBuffer(temp_array,new_size);
I2C0_SetAddressNackCallback(I2C0_SetRestartWriteCallback,NULL); //NACK polling?
I2C0_MasterWrite();
while(I2C0_BUSY == I2C0_Close()); // sit here until finished.
/* This function returns 0 if OK */
status = 0;
return status;
}
This works when sending an array that is located in my main.c file.
e.g:
//buffer.h
const uint8_t Sensor_Firmware[] = {0x05,...,0x01};
//End buffer.h
.
//main.c
void main (void)
{
uint8_t I2C_address = 0x01;
uint8_t I2C_reg = 0x01;
uint32_t size = 16;
uint8_t temp_array[size];
for (int i = 0; i <size; i++)
{
temp_array[i] = Sensor_Firmware[i];
}
WrMulti(I2C_address, I2C_reg, &temp_array[0], size);
While(1)
{
;
}
}
//End main.c
It also work when passing an array from the .h file without the 'const' key word.
e.g:
//buffer.h
uint8_t Sensor_Firmware[] = {0x05,...,0x01};
//End buffer.h
.
//main.c
void main (void)
{
uint8_t I2C_address = 0x01;
uint8_t I2C_reg = 0x01;
uint32_t size = 16;
uint8_t temp_array[size];
WrMulti(I2C_address, I2C_reg, &Sensor_Firmware[0], size);
While(1)
{
;
}
}
//End main.c
It does not when I pass the 'Sensor_Firmwware[]' array (with the const key word) from the .h file to 'WrMulti'. It just ends up sending '0x00' for every byte that comes from 'Sensor_Firmware'.
Does anyone know why this is might be?
Kind regards

Writing and reading data to EEPROM 24LC32A

I have been trying to write a byte to the EEPROM 23LC32A through I2C protocol. I am using uvision 5 Keil to code my program.
When I run my code in the Termite.exe terminal window, the output seems to indicate that read function is executing. It returns 255, which is the default value of a cleared EEPROM. So the thing is that the writing of the data is not taking place.
I have configured and coded the control registers correctly as per the datasheet. What could have possibly gone wrong? And also please do help with me page writing of EEPROM too. Here is my code below:
void write8eeprom(uint8_t addr, uint8_t reghigh, uint8_t reglow, uint8_t value)
{
uint8_t bytes [3];
bytes[0] = reghigh;
bytes[1] = reglow;
bytes[2] = value;
bool success = twi_master_transfer(addr, (uint8_t*) &bytes, sizeof(bytes), TWI_ISSUE_STOP);
}
uint8_t read8(uint8_t addr, uint8_t reg)
{
uint8_t value;
uint8_t bytes [1];
bytes[0] = reg;
uint8_t regValue[1] ;
twi_master_transfer(addr, (uint8_t*) &bytes, sizeof(bytes), TWI_DONT_ISSUE_STOP);
twi_master_transfer(addr|TWI_READ_BIT, (uint8_t*) &regValue, sizeof(regValue), TWI_ISSUE_STOP);
value = regValue[0] ;
return value;
}
void eeprom_write()
{
uint8_t value;
value = 1;
write8eeprom(160, 0x1000, 0x0001, value);
printf("Data %d is written\n", value);
}
void eeprom_read()
{
uint8_t value;
value = read8(160, 0x00000001);
printf("The data %d is read\n", value);
}
int main(void)
{
nrf_drv_clock_lfclk_request();
timers_init();
application_timers_start();
nrf_delay_ms(2000);
uart_config();
gpio_config();
bool tt= twi_master_init ( ) ;
nrf_delay_ms(2000);
printf("\n\r I2C \n\r");
eeprom_write();
nrf_delay_ms(1000);
eeprom_read();
for(;;)
{
__WFE();
}
}

Write to FRAM Memory Location in MSP430

I am working with MSP430 with FRAM Controller. And I Have to write a data from buffer over FRAM Location.
I have gone through bundled example of writing to FRAM.
unsigned long *FRAM_write_ptr;
unsigned long data;
#define FRAM_TEST_START 0xD000
data = 0x00010001;
void main
{
while(1)
{
data += 0x00010001;
FRAM_write_ptr = (unsigned long *)FRAM_TEST_START;
FRAMWrite(); // Endless loop
count++;
if (count > 100)
{
P1OUT ^= 0x01; // Toggle LED to show 512K bytes
count = 0; // ..have been written
data = 0x00010001;
}
}
}
void FRAMWrite(void)
{
unsigned int i=0;
for ( i= 0; i<128; i++)
{
*FRAM_write_ptr++ = data;
}
}
But When I tested example, It goes beyond the FRAM allocated section.
Is there any other method for writing on to FRAM.?

Data loss when converting byte to int on Arduino

I have a 3-byte array that buffers incoming bytes through the Serial port. Once it is full I want to use the bytes to call a function that takes a byte and an int as a parameter. This should theoretically not be a problem, but for some reason the bytes are not being converten into an int properly. Here is the code I have:
// for serialEvent()
uint8_t buffer[3] = {0, 0, 0};
uint8_t index = 0;
void serialEvent() {
while (Serial.available()) {
if (index > 2) {
// buffer is full so process it
uint16_t argument = (uint16_t)buffer[1];
argument <<= 8;
argument |= buffer[2];
processSerial(buffer[0], argument);
index = 0;
}
buffer[index] = Serial.read();
index++;
}
}
void processSerial(uint8_t action, uint16_t argument) { ... }
The problem appears to be in the line where the first bit is shifted to the left to make space for the second one. I have tried outputting the variable over the Serial port again and after the bit shift operation, it is 0.
The same thing happens when I try to replace the bit shift operation with a multiplication by 256 (which has the same result in theory).
Irritatingly, when I assign a static value like so, everything works fine:
uint16_t argument = 0x00CD;
argument <<= 8;
Is this a type cast problem? Am I missing something here?
Have not found the solution as to why this happens, but using the word() function does exactly what I want:
uint16_t argument = word(buffer[1], buffer[2]);
processSerial(buffer[0], argument);
Annoyingly, it is defined as:
unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }

Resources