How to interface LM75A temperature IC with AVR - avr

I am trying to get the temperature data of LM75A which is connected to atmega8 microcontroller using i2c, and display the data to docklight using serial communication. I have written the code and the output I am getting is
FF 7F 0F
According to the datasheet, if I ignore FF then 7F 0F will lead to +125 C temperature. But i dont know if its right or wrong(and why to ignore FF). So i am confused in cracking the output I am getting. The code which I think is correct but if it is wrong please correct it.
CODE:
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
#include<util/delay.h>
#include <stdio.h>
//Serial tansmit
void serial_avr(char *str)
{
UCSRB=(1<<TXEN);
UCSRC=(1<<UCSZ1)|(1<<UCSZ0)|(1<<URSEL);
UBRRL=51;
for (unsigned int i=0;str[i]!=0;i++)
{
UDR=str[i];
while(!(UCSRA&(1<<UDRE)));
}
_delay_ms(500);
}
void i2c_init(void)
{
TWSR=0x00;
TWBR=0x47;
TWCR=0x04;
}
void i2c_start(void)
{
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
while ((TWCR & (1 << TWINT)) == 0);
}
void i2c_write(unsigned char data)
{
TWDR = data ;
TWCR = (1<< TWINT)|(1<<TWEN);
while ((TWCR & (1 <<TWINT)) == 0);
}
unsigned char i2c_read(unsigned char ackVal)
{
TWCR = (1<< TWINT) | (1<<TWEN) | (ackVal<<TWEA);
while (!(TWCR & (1 <<TWINT)));
return TWDR ;
}
void i2c_stop()
{
TWCR = (1<< TWINT)|(1<<TWEN)|(1<<TWSTO);
}
void main(void)
{
int i =23;
unsigned char temp[20];
i2c_init();
i2c_start();
i2c_write(0b10010001); //slave address for LM75A
i2c_stop();
i2c_init();
i2c_start();
i2c_write(0b00000000); //pointer register address of LM75A
i2c_stop();
i2c_init();
i2c_start();
temp[20] = i2c_read(1);
i2c_stop();
while(1)
{
serial_avr(temp);
_delay_ms(2000);
}
}
I am reading the temperature in array and I am getting the output as FF 7F 0F and when I initialise it as a normal char variable then I am getting the output as C4. I am confused, i dont know where I am missing the point. If there is any error in the code then please tell me and how to crack the output.??
Please help, thanks.!

The first obvious error is how you treat the array temp[20].
You only read one byte from the sensor, but then write the value off the end of the array. (The only valid spots in the array are temp[0] to temp[19]. temp[20] is past the memory allocated.) You should be reading 3 bytes from the sensor and storing them at temp[0] to temp[2].
The next error with temp is how you write it out over the serial. You should be writing all the bytes of the array, not all the bytes until a 0. You don't know the last byte of the array is 0, because it never had a string in it. A convenient thing to do would be to #define a value for the length of the array so you could refer to it in the declaration of the array and in the write function.
Until you fix these problems, it is hard to tell if the rest is working. I don't see how you can even know that the values form the sensor are FF 7F 0F.

Related

AVR Atmega32a USART library isn't working

/*
RC_Car_AVR.c
Created: 4/18/2018 7:55:07 PM
Author :
*/
#define F_CPU 16000000
#define BAUD 9600
#define TUBRR (((F_CPU / 16) / BAUD) - 1)
#include <avr/io.h>
#include <util/delay.h>
char Read;
void USART_Init(void){
UBRRL = TUBRR;
UCSRB = (1<<TXEN)|(1<<RXEN);
UCSRC = (1<<UCSZ1)|(1<<UCSZ0);
}
char USART_Receive(void){
/* Wait for data to be received */
while (!(UCSRA & (1<<RXC)));
/* Get and return received data from buffer */
return UDR;
}
int main(void){
USART_Init();
DDRB |= (1<<0);
PORTB |= (1<<0);
while (1){
Read = USART_Receive();
if(Read == 'F'){
PORTB ^= (1<<0);
_delay_ms(100);
}
}
}
I'm trying to toggle an LED when I receive a certain character through the Bluetooth module (HC05).
I've written the USART library just like the datasheet but it doesn't seem to work (I'm only concerned with the initialization and receiving code since I'm working on a half duplex system so i don't need the transmition part).
I'm using Atmega32a with a 16MHz external crystal Oscillator.
Please tell me if you find anything wrong.
Thanks in advance.
Your Initialization is wrong.
Try this
void USART_Init(void){
UBRRL = TUBRR;
UBRRH = TUBRR >> 8;
UCSRB = (1<<TXEN)|(1<<RXEN);
UCSRC = (1<<UCSZ1)|(3<<UCSZ0);
}
This is the following initialization code provided in data sheet of atmega32
void USART_Init( unsigned int baud )
{
/* Set baud rate */
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud;
/* Enable receiver and transmitter */
UCSRB = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 2stop bit */
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}
I know following datasheet is little overhead in beginning But eventually you will see all your answers are provided there.

setting an i2c register to high

I have this project that my boss asked me to do and the first step is to figure out how to set a given I2C register to high or low using the silicon lab library, if anyone knows any good sources for this type of problem please provide them thank you. The pic that I am using is the pic16f1823, I've already looked at the documentation of the pic but into only states how to read and write to an I2c.
I use this as a header file and seems to work well for PIC16F1827 which is basically the same as the 1823. It used the peripheral of the PIC. Just include in in any c file you want to use i2c in. Make sure you #define FOSC in order to calculate the correct baud rate. Also double check the port and tris assignments are correct for your device and make adjustments.
It uses polling instead of an interrupt. Uncomment the interrupt setup code and write an interrupt service routine to catch the interrupts.
#ifndef I2C_H
#define I2C_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Hi-Tech C I2C library for 12F1822
* Master mode routines for I2C MSSP port to read and write to slave device
* Copyright (C)2011 HobbyTronics.co.uk 2011
* Freely distributable.
*/
#define I2C_WRITE 0
#define I2C_READ 1
// Initialise MSSP port. (12F1822 - other devices may differ)
void i2c_Init(void){
// Initialise I2C MSSP
// Master 100KHz
TRISB2 = 1;
TRISB5 = 1;
SSP1CON1 = 0b00101000; // I2C Master mode
SSP1CON2 = 0b00000000;
SSP1CON3 = 0b00000000;
//SSP1MSK = 0b00000000;
SSP1ADD = I2C_BRG; // clock = FOSC/(4 * (SSPxADD+1))
//SSP1IE = 1; // enable interrupt
SSP1STAT = 0b10000000;
}
// i2c_Wait - wait for I2C transfer to finish
void i2c_Wait(void){
while ( ( SSP1CON2 & 0x1F ) || ( SSPSTAT & 0x04 ) );
}
// i2c_Start - Start I2C communication
void i2c_Start(void)
{
i2c_Wait();
SSP1CON2bits.SEN=1;
}
// i2c_Restart - Re-Start I2C communication
void i2c_Restart(void){
i2c_Wait();
SSP1CON2bits.RSEN=1;
}
// i2c_Stop - Stop I2C communication
void i2c_Stop(void)
{
i2c_Wait();
SSP1CON2bits.PEN=1;
}
// i2c_Write - Sends one byte of data
void i2c_Write(unsigned char data)
{
i2c_Wait();
SSPBUF = data;
}
// i2c_Address - Sends Slave Address and Read/Write mode
// mode is either I2C_WRITE or I2C_READ
void i2c_Address(unsigned char address, unsigned char mode)
{
unsigned char l_address;
l_address=address<<1;
l_address+=mode;
i2c_Wait();
SSPBUF = l_address;
}
// i2c_Read - Reads a byte from Slave device
unsigned char i2c_Read(unsigned char ack)
{
// Read data from slave
// ack should be 1 if there is going to be more data read
// ack should be 0 if this is the last byte of data read
unsigned char i2cReadData;
i2c_Wait();
SSP1CON2bits.RCEN=1;
i2c_Wait();
i2cReadData = SSPBUF;
i2c_Wait();
if ( ack ) SSP1CON2bits.ACKDT=0; // Ack
else SSP1CON2bits.ACKDT=1; // NAck
SSP1CON2bits.ACKEN=1; // send acknowledge sequence
return( i2cReadData );
}
#ifdef __cplusplus
}
#endif
#endif /* I2C_H */
Then you can use the higher level functions defined above to control a device, which is described in the datasheet of the slave device.
For example, to read from an eeprom:
#include <xc.h>
#define FOSC 16000000
#include "i2c.h"
unsigned char i2c_read_eeprom( unsigned char slaveaddress, unsigned char memaddress )
{
unsigned char data;
data = 123;
i2c_Start();
i2c_Address( slaveaddress, I2C_WRITE);
i2c_Write(memaddress);
if( SSP1CON2bits.ACKSTAT )
txstring("ACK!\r\n");
else txstring("nACK!\r\n");
i2c_Start();
i2c_Address( slaveaddress, I2C_READ);
data = i2c_Read(0);
i2c_Stop();
return data;
}

How to access GPIO from kernel space? (zynq-microzed board)

I am using zynq-microzed board and I want to access GPIO with kernel space.
Can anyone please tell me how can i attempt doing this?
*NOTE: This is from the Zynq-7000. I believe it's largely the same.
Assuming you're using a devicetree, this is an example entry (in the devicetree):
gpio-device {
compatible = "gpio-control";
gpios = <&gpio0 54 0>; //(Add 32 to get the actual pin number. This is GPIO 86)
};
And you need to state in the driver that you're compatible with the devicetree entry (look at other drivers to see where to put this line):
.compatible = "gpio-control"
In your driver, include #include <linux/gpio.h> and read the pin from the devicetree:
struct device_node *np = pdev->dev.of_node;
int pin;
pin = of_get_gpio(np, 0);
if (pin < 0) {
pr_err("failed to get GPIO from device tree\n");
return -1;
}
Request the use of the GPIO:
int ret = gpio_request(pin, "Some name"); //Name it whatever you want
And set it's direction:
int ret = gpio_direction_output(pin, 0); //The second parameter is the initial value. 0 is low, 1 is high.
Afterwards, set the value like so:
gpio_set_value(pin, 1);
For input:
ret = gpio_direction_input(pin);
value = gpio_get_value(pin);
Free the GPIO when you're finished with it (including on error!):
gpio_free(pin);
At the end of the day, a good method is to grep around the kernel to find drivers that do what you want. In fact grep -r gpio <<kernel_source>> will tell you everything in this answer and more.
Check the following link: enter link description here
Summarizing:
There is an include file for working with GPIOs:
#include <linux/gpio.h>
GPIOs must be allocated before use:
int gpio_request(unsigned int gpio, const char *label);
And GPIO can be returned to the system with:
void gpio_free(unsigned int gpio);
Configure GPIO as Input/Output:
int gpio_direction_input(unsigned int gpio);
int gpio_direction_output(unsigned int gpio, int value);
Operations:
int gpio_get_value(unsigned int gpio);
void gpio_set_value(unsigned int gpio, int value);
Regards.

Keyboard interrupt handler for own kernel (C)

I am writing a tiny OS as part of an assigment for school,but I got stuck when it comes to get keyboard input (press a key -> display it on screen). I am using the Bare Bones tutorial from osdev.org (gcc cross-compiler, GRUB bootloader, ld linker) and since I am in protected mode I can not use BIOS interrupts for input, that's why I have to write my own interrupt handler (?) but I'm not sure how to do that even after I read some osdev articles and forum discussions. Very similar problem (http://forum.osdev.org/viewtopic.php?f=1&t=9746) except that I don't know how to "set up the interrupts".
#if !defined(__cplusplus)
#include <stdbool.h> /* C doesn't have booleans by default. */
#endif
#include <stddef.h>
#include <stdint.h>
#define INT_DISABLE 0
#define INT_ENABLE 0x200
#define PIC1 0x20
#define PIC2 0xA0
#define ICW1 0x11
#define ICW4 0x01
void outb( unsigned short port, unsigned char val )
{
asm volatile("outb %0, %1" : : "a"(val), "Nd"(port) );
}
static __inline unsigned char inb (unsigned short int port)
{
unsigned char _v;
__asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (port));
return _v;
}
void init_pics(int pic1, int pic2)
{
/* send ICW1 */
outb(PIC1, ICW1);
outb(PIC2, ICW1);
/* send ICW2 */
outb(PIC1 + 1, pic1);
outb(PIC2 + 1, pic2);
/* send ICW3 */
outb(PIC1 + 1, 4);
outb(PIC2 + 1, 2);
/* send ICW4 */
outb(PIC1 + 1, ICW4);
outb(PIC2 + 1, ICW4);
/* disable all IRQs */
outb(PIC1 + 1, 0xFF);
}
/*irrelevant code*/
#if defined(__cplusplus)
extern "C" /* Use C linkage for kernel_main. */
#endif
void kernel_main()
{
terminal_initialize();
char c;
init_pics(0x20, 0x28);
c = inb(0x60);
terminal_putchar(c);
}
This is printing me a white box.If I try listening to port 0x64 I get some different character. I don't expect this to work, because I don't have the interrupt. I think it should be something like
void _interrupt button_pressed()
{
/*code*/
}
if(button_pressed)
{
c = inb(0x60);
//code to translate the char to ASCII
terminal_putchar(asciiChar);
}
Any help is appreciated. Thanks
If there is someone interested how I solved the problem, here is the solution
char c = 0;
init_pics(0x20, 0x28);
do
{
if(inb(0x60)!=c) //PORT FROM WHICH WE READ
{
c = inb(0x60);
if(c>0)
{
terminal_putinput(c); //print on screen
}
}
}
while(c!=1); // 1= ESCAPE
c variable contains the code of the pressed button. Creating a translation array by associating to each code, the corresponding ASCII code, I can print the letter/number which is written on button.
The buttons code can be found here: http://www.nondot.org/sabre/os/files/HCI/keyboard.txt
The ASCII here: http://www.ascii-code.com/

SIGSEGV handler and mprotect and looping effect when injecting instructions at runtime. Handler can't get info->si_addr

I have looked at the various topics relating to this, but couldn't find this specific issue I am having.
Things I looked at:
Injecting code into executable at runtime
C SIGSEGV Handler & Mprotect
Can I write-protect every page in the address space of a Linux process?
How to write a signal handler to catch SIGSEGV?
I am able to handle SIGSEGV gracefully when the protection needs to be set to either PROT_READ or PROT_WRITE in the handler. However, when I try to inject instructions with mmap, and then use mprotect to set it to PROT_READ only, and then I execute the instructions via inline assembly, it causes a SIGSEGV as intended, but the handler is unable to get the originating address causing the signal, so I am unable to mprotect it to PROT_READ | PROT_EXEC.
Example:
void sigHandler(int signum, siginfo_t *info, void *ptr) {
printf("Received signal number: %d\n", signum);
printf("Signal originates from process %lu\n",
(unsigned long)info->si_pid);
printf("SIGSEGV caused by this address: ? %p\n", info->si_addr);
char * alignedbaseAddr = (((unsigned int)(info->si_addr)) >> 12) * getPageSize();
printf("Aligning to %p\n", alignedbaseAddr);
//flip this page to be r+x
mprotect(alignedbaseAddr, getPageSize(), PROT_READ | PROT_EXEC);
}
void setupSignalHandler() {
action.sa_sigaction = sigHandler;
action.sa_flags = SA_SIGINFO;
sigemptyset(&action.sa_mask);
sigaction(SIGSEGV, &action, NULL);
}
int main(int argc, char *argv[]) {
char * baseAddr = (char*)mmap(NULL, getDiskSize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(baseAddr == MAP_FAILED) {
perror("Unable to mmap.");
}
printf("Process address space is %d\n", getDiskSize());
//no-op filler
for(int i = 0; i < (getDiskSize()) - 1; i++) {
baseAddr[i] = 0x90;
}
//ret instruction
baseAddr[i] = 0xc3;
if( mprotect(baseAddr, getDiskSize(), PROT_READ) == -1) {
perror("mprotect");
exit(1);
}
printf("Protecting addresses: %p to %p for READ_ONLY\n", baseAddr, baseAddr + getDiskSize() - 1);
setupSignalHandler();
__asm__
(
"call %%eax;"
: "=a" (output)
: "a" (baseAddr)
);
printf("Will this ever print?");
//close fd, and unmap memory
cleanUp();
return EXIT_SUCCESS;
}
Here is the resulting output:
Received signal number: 11
Signal originates from process 0
SIGSEGV caused by this address: ? (nil)
//the above output repeatedly loops, since it fails to "re mprotect" that page.
Architecture:
x86 32 bit
OS:
Ubuntu 11.04 - Linux version 2.6.38-12-generic (buildd#vernadsky) (gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4) )
Any ideas? The above logic works fine for simply read and writing into memory. Is there
a better way to execute instructions at runtime as opposed to inline assembly?
Thanks in advance!
In that case, the faulting address is the instruction pointer. Cast your third argument ptr (of your signal handler installed with SA_SIGINFO) to a ucontext_t, and retrieve the appropriate register, perhaps as (untested code!)
ucontext_t *uc = ptr;
void* faultyip = uc->uc_mcontext.gregs[REG_IP];
Read carefully /usr/include/sys/ucontext.h for more.
I'm interested to know why you are asking!!

Resources