I am a newbie with DACs, but basically, I have a FPGA (DE1-SOC) running Linux. Hooked up to it is a LTC2607 DAC. Everything is operating smoothly as far as Linux recognizing the DAC over I2C and everything.
My question is regarding how to generate a sinusoidal waveform using the cordic algorithm. I have an algorithm that outputs an array of 16 hex values.
{0x00003243, 0x00001DAC, 0x00000FAD, 0x000007F5, etc...}
The code that runs the I2c/DAC accepts a 16-bit "DAC Code", which then is converted to an analog output:
uint16_t LTC2607_code(float dac_voltage, float LTC2607_lsb, float LTC2607_offset)
{
uint16_t dac_code;
float float_code;
float_code = (dac_voltage - LTC2607_offset) / LTC2607_lsb; // Calculate the DAC code
float_code = (float_code > (floor(float_code) + 0.5)) ? ceil(float_code) : floor(float_code); // Round
if (float_code >= 65535.0) // Limits the DAC code to 16 bits
float_code = 65535.0;
dac_code = (uint16_t) (float_code); // Convert to unsigned integer
return (dac_code);
}
I know for direct digital synthesis you have to "interpolate" the points (voltage levels) along the sinusoid. My thinking is that I would send those value across the I2C, one-by-one, and however fast those 16 hex values are passed across the I2C (set by the Master (FPGA) clock # ~10MHz) is what frequency the sin wave will be?
The code for writing to the DAC is as follows:
int8_t LTC2607_write(uint8_t i2c_address, uint8_t dac_command, uint8_t dac_address, uint16_t dac_code)
{
int fd;
int ret;
char *device;
uint8_t command_byte;
uint8_t buffer[3];
command_byte = dac_command | dac_address; // Build the DAC command byte
// Open the I2C device
device = LTC2607_get_device_name();
fd = open(device, O_RDWR);
if (fd < 0)
{
return (1);
}
// Select the desired address
ret = ioctl(fd, I2C_SLAVE, i2c_address);
if (ret < 0)
{
close(fd);
return (1);
}
// Build the I2C command
buffer[0] = command_byte;
buffer[1] = (dac_code >> 8) & 0xFF;
buffer[2] = dac_code & 0xFF;
// Write the command to the I2C bus
ret = write(fd, buffer, 3);
if (ret < 3)
{
close(fd);
return (1);
}
// Close the device
close(fd);
return (0);
}
How would I convert that string of 16 hex values into a sinusoid using the above LTC2607_write function?
Related
I am currently having an issue with trying to connect my pi pico with the I2c adapter (LCM1602 of my 1602LCD display. I tried the official example from the raspberry pi github page (It is using the c/++ SDK for pi pico, but this was unsuccessful. I can compile/load the code, but nothing is displayed. I did a I2c bus scan and found out that the I2c address is indeed 0x27. So I know the pins and address are correct. I cant find a good datasheet that gives a overview of all commands for my type of adapter. They also do this weird thing in the code where the send a one byte command in six bytes ( void lcd_send_byte(uint8_t val, int mode) ). I am not very familiar with serial communication, so I dont know if this is normal. Can anybody maybe link a good reference datasheet for a LCM1602 I2c adapter or suggest what the best thing to do is from here?
Ps: I havent tried in micropython yet, but i prefer to do this in c.
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "pico/binary_info.h"
/* Example code to drive a 16x2 LCD panel via a I2C bridge chip (e.g. PCF8574)
NOTE: The panel must be capable of being driven at 3.3v NOT 5v. The Pico
GPIO (and therefor I2C) cannot be used at 5v.
You will need to use a level shifter on the I2C lines if you want to run the
board at 5v.
Connections on Raspberry Pi Pico board, other boards may vary.
GPIO 4 (pin 6)-> SDA on LCD bridge board
GPIO 5 (pin 7)-> SCL on LCD bridge board
3.3v (pin 36) -> VCC on LCD bridge board
GND (pin 38) -> GND on LCD bridge board
*/
// commands
const int LCD_CLEARDISPLAY = 0x01;
const int LCD_RETURNHOME = 0x02;
const int LCD_ENTRYMODESET = 0x04;
const int LCD_DISPLAYCONTROL = 0x08;
const int LCD_CURSORSHIFT = 0x10;
const int LCD_FUNCTIONSET = 0x20;
const int LCD_SETCGRAMADDR = 0x40;
const int LCD_SETDDRAMADDR = 0x80;
// flags for display entry mode
const int LCD_ENTRYSHIFTINCREMENT = 0x01;
const int LCD_ENTRYLEFT = 0x02;
// flags for display and cursor control
const int LCD_BLINKON = 0x01;
const int LCD_CURSORON = 0x02;
const int LCD_DISPLAYON = 0x04;
// flags for display and cursor shift
const int LCD_MOVERIGHT = 0x04;
const int LCD_DISPLAYMOVE = 0x08;
// flags for function set
const int LCD_5x10DOTS = 0x04;
const int LCD_2LINE = 0x08;
const int LCD_8BITMODE = 0x10;
// flag for backlight control
const int LCD_BACKLIGHT = 0x08;
const int LCD_ENABLE_BIT = 0x04;
// By default these LCD display drivers are on bus address 0x27
static int addr = 0x27;
// Modes for lcd_send_byte
#define LCD_CHARACTER 1
#define LCD_COMMAND 0
#define MAX_LINES 2
#define MAX_CHARS 16
/* Quick helper function for single byte transfers */
void i2c_write_byte(uint8_t val) {
#ifdef i2c_default
i2c_write_blocking(i2c_default, addr, &val, 1, false);
#endif
}
void lcd_toggle_enable(uint8_t val) {
// Toggle enable pin on LCD display
// We cannot do this too quickly or things don't work
#define DELAY_US 600
sleep_us(DELAY_US);
i2c_write_byte(val | LCD_ENABLE_BIT);
sleep_us(DELAY_US);
i2c_write_byte(val & ~LCD_ENABLE_BIT);
sleep_us(DELAY_US);
}
// The display is sent a byte as two separate nibble transfers
void lcd_send_byte(uint8_t val, int mode) {
uint8_t high = mode | (val & 0xF0) | LCD_BACKLIGHT;
uint8_t low = mode | ((val << 4) & 0xF0) | LCD_BACKLIGHT;
i2c_write_byte(high);
lcd_toggle_enable(high);
i2c_write_byte(low);
lcd_toggle_enable(low);
}
void lcd_clear(void) {
lcd_send_byte(LCD_CLEARDISPLAY, LCD_COMMAND);
}
// go to location on LCD
void lcd_set_cursor(int line, int position) {
int val = (line == 0) ? 0x80 + position : 0xC0 + position;
lcd_send_byte(val, LCD_COMMAND);
}
static void inline lcd_char(char val) {
lcd_send_byte(val, LCD_CHARACTER);
}
void lcd_string(const char *s) {
while (*s) {
lcd_char(*s++);
}
}
void lcd_init() {
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x02, LCD_COMMAND);
lcd_send_byte(LCD_ENTRYMODESET | LCD_ENTRYLEFT, LCD_COMMAND);
lcd_send_byte(LCD_FUNCTIONSET | LCD_2LINE, LCD_COMMAND);
lcd_send_byte(LCD_DISPLAYCONTROL | LCD_DISPLAYON, LCD_COMMAND);
lcd_clear();
}
int main() {
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
#warning i2c/lcd_1602_i2c example requires a board with I2C pins
#else
// This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
i2c_init(i2c_default, 100 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
lcd_init();
static char *message[] =
{
"RP2040 by", "Raspberry Pi",
"A brand new", "microcontroller",
"Twin core M0", "Full C SDK",
"More power in", "your product",
"More beans", "than Heinz!"
};
while (1) {
for (int m = 0; m < sizeof(message) / sizeof(message[0]); m += MAX_LINES) {
for (int line = 0; line < MAX_LINES; line++) {
lcd_set_cursor(line, (MAX_CHARS / 2) - strlen(message[m + line]) / 2);
lcd_string(message[m + line]);
}
sleep_ms(2000);
lcd_clear();
}
}
return 0;
#endif
}
I am currently having an issue with trying to connect my pi pico with the I2c adapter (LCM1602 of my 1602LCD display
Is this the I2C adapter you're talking about ?
I can compile/load the code, but nothing is displayed
Looks like you're trying to send char *message[] as data to the display. You may want to try to send any kind off data (for exemple 0xaa,0xbb,...) to test if you can actualy communicate. If you can, try to see what's happening with an oscilloscope.
The constrast may also be changed if you think you did every thing well.
I cant find a good datasheet that gives a overview of all commands for my type of adapter
Looks like it's only an interpreter. So it doesn't have commands. It only translate the I2C data to you display.
In hope this helps you.
I'm trying to interface vl53l0x sensor with my atSamE51A19 controller. I can send the data to the sensor. As it has established connection I send identification code and it responds. But further initialization and ranging is not working.
I'm using stm library implementation on my sam board. [stmArduinoLib][1]
The only changes I made is in the read write functions. It was using stm base functions but I'm using different functions.
/****************** Write and read functions from I2C *************************/
VL53L0X_Error VL53L0X::VL53L0X_WriteMulti(VL53L0X_DEV Dev, uint8_t index, uint8_t *pdata, uint32_t count)
{
int status;
status = VL53L0X_I2CWrite(index, pdata, (uint16_t) count);
if (status == 0)
{
status = VL53L0X_ERROR_CONTROL_INTERFACE;
}
else
{
status = VL53L0X_ERROR_NONE;
}
return status;
}
VL53L0X_Error VL53L0X::VL53L0X_ReadMulti(VL53L0X_DEV Dev, uint8_t index, uint8_t *pdata, uint32_t count)
{
int status;
if (count >= VL53L0X_MAX_I2C_XFER_SIZE)
{
status = VL53L0X_ERROR_INVALID_PARAMS;
}
status = VL53L0X_I2CRead(index, pdata, (uint16_t) count);
return status;
}
VL53L0X_Error VL53L0X::VL53L0X_WrByte(VL53L0X_DEV Dev, uint8_t index, uint8_t data)
{
int status;
status = WriteRegister(index, data); //VL53L0X_I2CWrite(index, &data, 1);
if (status == 0)
{
status = VL53L0X_ERROR_CONTROL_INTERFACE;
}
else
{
status = VL53L0X_ERROR_NONE;
}
return status;
}
VL53L0X_Error VL53L0X::VL53L0X_WrWord(VL53L0X_DEV Dev, uint8_t index, uint16_t data)
{
int status;
int32_t status_int;
alignas(2) uint8_t buffer[2];
buffer[0] = data >> 8;
buffer[1] = data & 0x00FF;
status_int = VL53L0X_I2CWrite(index, (uint8_t*) buffer, 2);
// buffer[0] = MSB
// buffer[1]
// buffer[2]
// buffer[3] = LSB
if (status_int == 0)
{
status = VL53L0X_ERROR_CONTROL_INTERFACE;
}
else
{
status = VL53L0X_ERROR_NONE;
}
return status;
}
VL53L0X_Error VL53L0X::VL53L0X_WrDWord(VL53L0X_DEV Dev, uint8_t index, uint32_t data)
{
int status;
int32_t status_int;
alignas(2) uint8_t buffer[4];
buffer[0] = (data >> 24) & 0xFF; // MSB
buffer[1] = (data >> 16) & 0xFF;
buffer[2] = (data >> 8) & 0xFF;
buffer[3] = (data >> 0) & 0xFF; // LSB
status_int = VL53L0X_I2CWrite(index, buffer, 4);
if (status_int == 0)
{
status = VL53L0X_ERROR_CONTROL_INTERFACE;
}
else
{
status = VL53L0X_ERROR_NONE;
}
return status;
}
VL53L0X_Error VL53L0X::VL53L0X_RdByte(VL53L0X_DEV Dev, uint8_t index, uint8_t *data)
{
int status = VL53L0X_ERROR_NONE;
status = ReadRegister(index, *data); //
if (status)
{
status = VL53L0X_ERROR_NONE;
return status;
}
else
{
status = VL53L0X_ERROR_CONTROL_INTERFACE;
}
return status;
}
VL53L0X_Error VL53L0X::VL53L0X_RdWord(VL53L0X_DEV Dev, uint8_t index, uint16_t *data)
{
int status = 0;
uint8_t buffer[2] =
{ 0, 0 };
status = VL53L0X_I2CRead(index, buffer, 2);
if (status == 0)
{
*data = (uint16_t) (buffer[0] << 8) | (buffer[1] & 0xFF); // | ? +
}
return status;
}
VL53L0X_Error VL53L0X::VL53L0X_RdDWord(VL53L0X_DEV Dev, uint8_t index, uint32_t *data)
{
int status;
uint8_t buffer[4] =
{ 0, 0, 0, 0 };
status = VL53L0X_I2CRead(index, buffer, 4);
if (!status) // use OR
{
*data = ((uint32_t) buffer[0] << 24) | ((uint32_t) buffer[1] << 16) | ((uint32_t) buffer[2] << 8) | (uint32_t) buffer[3];
}
return status;
}
VL53L0X_Error VL53L0X::VL53L0X_UpdateByte(VL53L0X_DEV Dev, uint8_t index, uint8_t AndData, uint8_t OrData)
{
int status;
uint8_t buffer = 0;
/* read data direct onto buffer */
status = VL53L0X_I2CRead(index, &buffer, 1);
if (!status)
{
buffer = (buffer & AndData) | OrData;
status = VL53L0X_I2CWrite(index, &buffer, (uint8_t) 1);
}
if (status == 0)
{
status = VL53L0X_ERROR_CONTROL_INTERFACE;
}
else
{
status = VL53L0X_ERROR_NONE;
}
return status;
}
VL53L0X_Error VL53L0X::VL53L0X_I2CWrite(uint8_t RegisterAddr, uint8_t *pBuffer, uint16_t NumByteToWrite)
{
return WriteRegisters(RegisterAddr, pBuffer, NumByteToWrite);
}
VL53L0X_Error VL53L0X::VL53L0X_I2CRead(uint8_t RegisterAddr, uint8_t *pBuffer, uint16_t NumByteToRead)
{
alignas(2) uint8_t vpBuffer[5];
/* dev_i2c->beginTransmission(((uint8_t) (((DeviceAddr) >> 1) & 0x7F)));
*/
if (ReadRegisters(RegisterAddr, vpBuffer, NumByteToRead))
{
pBuffer = vpBuffer;
return 0;
}
return 1;
}
In this functions I'm not sending device address everytime just sending the index and data. In constructor only I've set the address once. The only error I'm getting when I use Status = VL53L0X_PerformRefSpadManagement(Device, &refSpadCount, &isApertureSpads); This function. In initialization. Don't know how to solve this issue. Tried to change the mode to continous that didn't help. Note: the sensor is working fine with arduino.
[1]: https://github.com/stm32duino/VL53L0X
I found a new possible solution to this problem, as I spent 2 days to solve it, I feel that I need to share it with you guys. Here is the summary of solutions:
Powering problem 1: add a 50ms delay in the setup function (before the sensor init, obviously). This way, the Vin will have time enough to reach the level needed by the sensor, as explained in a previous message (ocrdu)
Powering problem 2: This sensor demands more than others, normally the 5V pin of your board will do it better than the 3v3. If there are many sensors connected at the same time, disconnect all of them to check whether they are using the power our vl53l0x needs.
Powering problem 3: If you feed it with an external source, unify grounds with the board, don't forget it
SCL - SDA weak signals: add a pullup (2k2 - 4k7 from each channel to vin), this way the signals will perform better, that could be the problem
Soldering problem: Make sure that each header pin is well soldered. I've found many cases of poor soldering. The tiny pads don't help. It is advisable to check continuity with a multimeter between the headers and the pads where they should be connected
XSHUT not pulled up: My problem, this was that AZDelivery board says that it has a pull up in XSHUT (which works like an enable). But it could either be false, or badly implemented. Xshut needs to be high, 3v3/5v, otherwise, the sensor won't work. Bridge the XSHUT to Vin or implement a pull up and the problem will be solved.
I am using adafruit's library 1.1.2, and it works, with pullups, without pullups, connected to 5V and also connected to 3V3, with the
50ms delay, and connecting XSHUT to high (3V3 / Vin)
My board is vl53l0x from AZDelivery (5€ amazon)
I have tested the sensor with arduino nano and with ESP32, both work fine
Hope you guys find this useful <3
i'm monitorating heart rate by the MAX30100(https://img.filipeflop.com/files/download/Datasheet_MAX30100.pdf) using the MCU STM32F4. I'm trying read the IR and RED data from the FIFO, but all returns are ZERO. The method MAX30100_Get_Num_Samples() returns 8. I modeled the code using the pseudo code from datasheet of MAX30100. I tried several solutions for my problem but doesn't work. I dont know if i'm following the right way to get data from the FIFO. My code:
I2C_HandleTypeDef hi2c3; //i2c used
uint16_t RED[50] = {0}, IR[50] = {0}; //buffers for RED and IR
uint8_t buffOximeter[5];
char buffer[32];
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C3_Init();
MX_USB_DEVICE_Init();
MAX30100_Init();
while (1)
{
uint8_t numSamples = MAX30100_Get_Num_Samples();
MAX30100_Read_HeartBeat(numSamples);
for(int i = 0; i < numSamples; i++)
{
sprintf(buffer, "Amostra %d: %d / %d\n\r", i , IR[i], RED[i]);
CDC_Transmit_FS((char*)buffer, 50);
}
}
}
static void MX_I2C3_Init(void)
{
hi2c3.Instance = I2C3;
hi2c3.Init.ClockSpeed = 400000;
hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c3.Init.OwnAddress1 = 0;
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c3) != HAL_OK)
{
Error_Handler();
}
}
void MAX30100_Init(void)
{
HAL_I2C_Mem_Write(&hi2c3,0xAE,0x06,1,0x02,1,1000); //set heart rate mode
HAL_I2C_Mem_Write(&hi2c3,0xAE,0x09,1,0xFF,1,1000); //i50 ledCurrent
uint8_t sr = 0x01, pw = 0x3;
HAL_I2C_Mem_Write(&hi2c3,0xAE,0x07,1,(sr<<2)|pw,1,1000); //sr100, pw1600
HAL_Delay(50);
}
void MAX30100_Read_HeartBeat(uint8_t num)
{
for(int i=0;i<num;i++)
{
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAE,1,1000); //adress + write mode
HAL_I2C_Master_Transmit(&hi2c3,0x57,0x02,1,1000); //send fifo_wr_ptr
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAF,1,1000); //adress + read mode
uint8_t data;
HAL_I2C_Master_Receive(&hi2c3,0x57,&data,1,1000); //read fifo_wr_ptr
HAL_Delay(100); //STOP
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAE,1,1000); //adress + write mode
HAL_I2C_Master_Transmit(&hi2c3,0x57,0x05,1,1000); //send adress fifo data
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAF,1,1000); //adress + read mode
HAL_I2C_Mem_Read(&hi2c3,0x57,0x05,1,&buffOximeter,4,1000); //read fifo data
IR[i] = (buffOximeter[0] << 8) | buffOximeter[1];
RED[i] = (buffOximeter[2] << 8) | buffOximeter[3];
HAL_Delay(100); //STOP
HAL_I2C_Master_Transmit(&hi2c3,0x57,0xAE,1,1000); //adress + write mode
HAL_I2C_Master_Transmit(&hi2c3,0x57,0x04,1,1000); //send adress fifo_rd_ptr
HAL_Delay(100);
}
}
int MAX30100_Get_Num_Samples(void)
{
uint8_t wrPtr, rdPtr;
HAL_I2C_Mem_Read(&hi2c3,0x57,0x02,1,&wrPtr,1,1000);
HAL_Delay(50);
HAL_I2C_Mem_Read(&hi2c3,0x57,0x04,1,&rdPtr,1,1000);
HAL_Delay(50);
return (abs( 16 + wrPtr - rdPtr ) % 16);
}
connect the interrupt output pin (pin 13 active low) to an interrupt control pin on the cpu.
setup your cpu to be interrupted when the device indicates some event ready
Then, still in your interrupt handler function, read register 0 and determine which data is ready,.
the referenced datasheet, approx page 14 lists the order of communication events needed. Note that the posted code is NOT following the specified order of communication events
page 16, register 7, indicates how to initialize the SPO2 for the desired mode of operation
I'm beginner to micro controller technology. I want to transmit the 10-bit output I got from an Analog to Digital Conversion, but only 8 bits can be sent via the UART. How can I send 10 bits?
Please help me to write C code to solve this problem. My code so far is given below. The compiler used is XC8.
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
#define _XTAL_FREQ 4000000
#include <stdio.h>
#include <stdlib.h>
#include <htc.h>
void uart_init(void);
void TX(unsigned char TX_BYTE);
void configure_pins();
unsigned char read_input(unsigned char channel);
void main()
{
__delay_ms(2);
while (1) {
TRISB = 0; //configuring portB as output
TRISC = 0;
TRISA = 1;
configure_pins(); //calling methods
unsigned char x = read_input(0);
uart_initialize();
assign_data_to_tx_pin(x);
}
}
void configure_pins(){
ADCON1 = 0b10000000; //The result is right justified
}
unsigned char read_input(unsigned char channel){ // converting the Analog input to digital
ADCON0=0b00000000;
CHS0=0; // AN0 is selected
CHS1=0; // "
CHS2=0; // "
ADON = 1;
GO_DONE = 1;
while (GO_DONE);
ADON = 0;
return ((ADRESH >> 2) + ADRESL); // return the result of conversion
}
void uart_initialize(void) // initializing the UART for data transmission
{
TRISC = 0; //configuring portC as output
TXSTA = 0b100000000;
TXEN = 1; //enable transmission mode
SPEN = 1; //enable UART
BRGH = 0; //enable low baud
SPBRG = 6; //set baud rate as 9600
SYNC = 0; //enable asynchronous transmission
RCIE = 1;
GIE = 1;
PEIE = 1;
}
void assign_data_to_tx_pin(unsigned char converted_data) { // assigning the data to the Tx pin for transmission
while(!TRMT) {
unsigned char a = converted_data;
TXREG = a;
TXREG = a >> 2;
PORTCbits.RC6 = TXREG;
__delay_ms(100); // Delay
}
}
Typical UARTs do not allow for more than 8 bits of data per transmission. Some allow 9. Sending 10 bits may be available on select UARTS using 9 bits and controlling the parity, but that is rare.
Instead recommend to send the data as 2 transmission with a bit set aside to denote which half is sent.
Send_ADC(void){
ADCON0=0b00000000;
CHS0=0; // AN0 is selected
CHS1=0; // "
CHS2=0; // "
ADON = 1;
GO_DONE = 1;
while (GO_DONE);
ADON = 0;
unsigned adc10 = ((ADRESH >> 2) + ADRESL);
assign_data_to_tx_pin((adc10 % 32) * 2 + 0); // 00lllll0
assign_data_to_tx_pin((adc10 / 32) * 2 + 1); // 00hhhhh1
}
On receiver side, insure bytes received are in the proper byte order. This will re-construct the received data in the proper order, even if reception does not start in phase or if a byte was lost in communication.
// return 0: success, else 1
int ReadSerialADC(unsigned *data) {
unsigned adc;
unsigned low = read_from_comport();
if (low %2) return 1;
low /= 2;
unsigned high = read_from_comport();
if (high %2 == 0) return 1;
high /= 2;
*data = high * 32 + low;
return 0;
}
You are reading a 10-bit ADC result with like this
return ((ADRESH>>2)+ADRESL);
But the function is return unsigned char, it should be unsigned int
unsigned int read_input(unsigned char channel)
and the calling function is also throwing away two bits with
unsigned char x=read_input(0);
which should be
unsigned int x=read_input(0);
Having read a 10-bit value into a (presumably) 16-bit variable, you now have to transmit it to the serial port. Let's do this by sending the most significant 8 bits first.
TX (x >> 8);
TX (x & 0xFF);
Then at the receiver end you read the two bytes and put them back together
unsigned adcval = RX() << 8;
adcval |= RX();
I'm trying to program a digital thermometer DS18B20 on 1-Wire using UART and I have weird problems. When I'm debugging this program that runs without breakpoints (or just running program without debugging) I have readings about 100°C. When I put breakpoint before receiving temperature information, it gives me about 50°c. And 3rd option when I just open this window when I can see SFRs and expand UART4 section it gives me proper readings about 25°C. I have Saleae logic analyzer and in all these 3 cases it sends me valid data (about 25°C). I tried to put some delay where breakpoint is (even 2s delay) and it doesn't help. It gives me readings about 50°C (like with breakpoints and not expanded SFRs window). This is probably programming error (I'm starting), but this action with expanded SFRs window is beyond my reasoning.
I really don't know what's going on. I hope you can put some light on this situation for me.
I'm using STM32F4-Discovery evaluation board and programming it on Atollic 4.1.0.
My "Library" file:
#include "DS18B20_Lib.h"
void DS18B20_Init(void)
{
//USART4 PA0
GPIO_InitTypeDef GS;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_UART4);
GS.GPIO_Mode = GPIO_Mode_AF;
GS.GPIO_OType = GPIO_OType_PP;
GS.GPIO_PuPd = GPIO_PuPd_UP;
GS.GPIO_Speed = GPIO_Speed_50MHz;
GS.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA,&GS);
USART_InitTypeDef US;
US.USART_BaudRate = 115200;
US.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
US.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
US.USART_Parity = USART_Parity_No;
US.USART_StopBits = USART_StopBits_1;
US.USART_WordLength = USART_WordLength_8b;
USART_Init(UART4,&US);
USART_SetAddress(UART4,0x12);
USART_Cmd(UART4,ENABLE);
USART_HalfDuplexCmd(UART4,ENABLE);
USART_ITConfig(UART4,USART_IT_TXE | USART_IT_RXNE | USART_IT_TC ,ENABLE);
/*NVIC_InitTypeDef NS;
NS.NVIC_IRQChannel = UART4_IRQn;
NS.NVIC_IRQChannelCmd = ENABLE;
NS.NVIC_IRQChannelPreemptionPriority = 1;
NS.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NS);*/
}
uint16_t Reset_1Wire(void)
{
uint16_t Present;
while (USART_GetFlagStatus(UART4, USART_FLAG_TC) == RESET);
UART4->BRR = 0x1117;
while (USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET);
USART_SendData(UART4,0xF0);
while (USART_GetFlagStatus(UART4, USART_FLAG_RXNE) == RESET);
Present = USART_ReceiveData(UART4);
while (USART_GetFlagStatus(UART4, USART_FLAG_TC) == RESET);
UART4->BRR = 0x016D;
return Present;
}
char Read_1Wire(void)
{
char Data=0;
int i;
for(i=0;i<8;i++)
{
while (USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET);
USART_SendData(UART4,0xFF);
while (USART_GetFlagStatus(UART4, USART_FLAG_RXNE) == RESET);
if(USART_ReceiveData(UART4)==0xFF)
Data|=0x80;
else Data|=0;
if (i!=7) Data=Data>>1;
}
return Data;
}
void Write_1Wire(char Data)
{
char Mask=1;
int i;
for(i=0;i<8;i++)
{
while (USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET);
if (Data & Mask)
USART_SendData(UART4,0xFF);
else
USART_SendData(UART4,0x00);
Mask=Mask<<1;
}
}
uint16_t DS18B20_MeasTemp(void)
{
uint16_t Data;
uint16_t LSB;
uint16_t MSB;
Reset_1Wire();
Write_1Wire(0xCC); //SkipRom only 1 device
Write_1Wire(0x44);
while(Read_1Wire()==0x00);
Reset_1Wire();
Write_1Wire(0xCC);
Write_1Wire(0xBE);
/*--------BRAKEPOINT HERE--------*/
LSB=Read_1Wire();
MSB=Read_1Wire();
Data=MSB<<8|LSB;
Reset_1Wire();
return Data;
}
And my main function:
int main(void)
{
char strLine[25];
uint16_t Temperature;
LCD_Init();
LCD_SetColors(GREEN, BLUE);
LCD_Clear(BLUE);
LCD_CharSize(16);
DS18B20_Init();
sprintf(strLine,"%s","Temp: ");
LCD_StringLine(20,50,(uint8_t*) strLine);
//GPIO_Config();
while (1)
{
Presence1Wire();
Temperature = DS18B20_MeasTemp();
if (Temperature&0xF000)
LCD_PutChar(60,50,'-');
else LCD_PutChar(60,50,'+');
LCD_PutInt(68,50,(Temperature&0x0FF0)>>4);
LCD_PutInt(72,64,(Temperature&0xF)*625);
}
}
Write_1Wire(0xCC);
Write_1Wire(0xBE);
send bytes to UART and no read. Receive data in fifo.
Read_1Wire()
read old this data in fifo.
uint16_t DS18B20_MeasTemp(void)
{
uint16_t Data;
uint16_t LSB;
uint16_t MSB;
Reset_1Wire();
Write_1Wire(0xCC); //SkipRom only 1 device
Write_1Wire(0x44);
while(Read_1Wire() == 0x00);
Reset_1Wire();
Write_1Wire(0xCC);
Write_1Wire(0xBE);
/*--------BRAKEPOINT HERE--------*/
// !!!!!!! Paste this
while (USART_GetFlagStatus(UART4, USART_FLAG_RXNE) != RESET)
USART_ReceiveData(UART4);
// !!!!!!!
LSB = Read_1Wire();
MSB = Read_1Wire();
Data = MSB << 8 | LSB;
Reset_1Wire();
return Data;
}
I've also encountered a similar problem, I was measuring capacitance of a capacitance water level sensor and while running in debugging I got different values than in run mode without the usage of debugger (just plainly connecting it to an external power supply).
I think the issue is with the architecture of the processor, when you are debugging the breakpoint it pauses the cpu but not the peripheral clocks, and GPT aren't getting paused which gives different readings since my measurements are timer dependent.
I'm speaking from my perspective so it might not be happening in your case but it could give you a different view to the problem.