Simple expansion board to log the room temperature.
main.c
#include <avr/io.h>
#include <avr/boot.h>
#include <util/delay.h>
#include <avr/signature.h>
#include <avr/pgmspace.h>
#include <stdint.h>
#include <stdbool.h>
#include <avr/eeprom.h>
#include <usart.h>
#include "ad.h"
union {
uint16_t data[2];
uint8_t bytes[8]; // buffer
} ad_data;
uint8_t spi_count;
int main(void)
{
usart_init_38400();
ad_init();
DDRD = _BV(2);
DDRB = _BV(4); // MOSI
SPCR = _BV(SPIE) | _BV(SPE); // enable SPI, Interrupt and slave mode
PCMSK0 = _BV(PCINT2);
PCICR = _BV(PCIE0);
sei();
// usart_putstr_P(PSTR("Small Test\r\n"));
while(1) {
_delay_ms(1000);
uint16_t temp_ad = 0;
uint8_t i = 0, j = 0;
for (i = 0; i < 8; i++) {
temp_ad += ad_get(0);
}
float temp = ((temp_ad/8.0)*3.3*1000/(1 << 10)-600)/10.0;
printf_P(PSTR("%f %3u %02x\n"), temp, ad_get(1), PINB & _BV(2));
for (j = 0; j < 2; j++) {
uint16_t ad_temporary = 0;
for (i = 0; i < 0x10; i++) {
ad_temporary += ad_get(j);
}
ad_data.data[j] = ad_temporary;
}
}
}
ISR(SPI_STC_vect)
{
//uint8_t a = SPDR;
//SPDR = a;
//printf_P(PSTR("%02x!"), a);
SPDR = ad_data.bytes[++spi_count];
usart_putc('.');
}
ISR(PCINT0_vect)
{
if (PINB & _BV(2)) {
PORTD |= _BV(2);
} else {
PORTD &= ~_BV(2);
spi_count = 0;
SPDR = ad_data.bytes[0];
}
}
ad.c
#include "ad.h"
void ad_init(void)
{
ADCSRA = _BV(ADEN) | _BV(ADPS2);
}
uint16_t ad_get(uint8_t num)
{
ADMUX = (num & 0xf) | _BV(REFS0);
ADCSRA |= _BV(ADSC);
while(!(ADCSRA & _BV(ADIF)));
uint16_t data = ADC;
ADCSRA &= ~_BV(ADIF);
return data;
}
usart.c / usart.h
Please download from Github
/*
* Copyright (c) 2012 Y.Okamura
*
* Based on http://elinux.org/Rpi_Low-level_peripherals
* How to access GPIO registers from C-code on the Raspberry-Pi
* 15-January-2012
* Dom and Gert
*
* Based on http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob_plain;f=Documentation/spi/spidev_test.c
* SPI testing utility (using spidev driver)
*
* Copyright (c) 2007 MontaVista Software, Inc.
* Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*/
// Access from ARM Running Linux
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static void pabort(const char *s)
{
perror(s);
abort();
}
#include <unistd.h>
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
int mem_fd;
char *gpio_mem, *gpio_map;
char *spi0_mem, *spi0_map;
// I/O access
volatile unsigned *gpio;
int spi_fd;
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
#define SPEED 10000
#define BITS 8
void setup_io();
void setup_spi();
static void transfer(int fd);
int main(int argc, char **argv)
{
int g,rep;
// Set up gpi pointer for direct register access
setup_io();
INP_GPIO(25); // Slave Select
OUT_GPIO(25);
GPIO_CLR = 1 << 25;
setup_spi();
transfer(spi_fd);
GPIO_SET = 1 << 25;
close(spi_fd);
return 0;
} // main
//
// Set up a memory regions to access GPIO
//
void setup_io()
{
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem \n");
exit (-1);
}
/* mmap GPIO */
// Allocate MAP block
if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
printf("allocation error \n");
exit (-1);
}
// Make sure pointer is on 4K boundary
if ((unsigned long)gpio_mem % PAGE_SIZE)
gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);
// Now map it
gpio_map = (unsigned char *)mmap(
(caddr_t)gpio_mem,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
GPIO_BASE
);
if ((long)gpio_map < 0) {
printf("mmap error %d\n", (int)gpio_map);
exit (-1);
}
// Always use volatile pointer!
gpio = (volatile unsigned *)gpio_map;
} // setup_io
void setup_spi(void)
{
int ret = 0;
spi_fd = open("/dev/spidev0.0", O_RDWR);
/*
* bits per word
*/
int bits = 8;
ret = ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word");
ret = ioctl(spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word");
/*
* max speed hz
*/
int speed = 10000;
ret = ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz");
ret = ioctl(spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz");
}
static void transfer(int fd)
{
int ret;
uint8_t tx[] = {
0xff, 0x00, 0x00, 0x00
};
union {
uint16_t data[2];
uint8_t bytes[8]; // buffer
} ad_data;
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)ad_data.bytes,
.len = ARRAY_SIZE(tx),
.delay_usecs = 0,
.speed_hz = SPEED,
.bits_per_word = BITS,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
/* for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { */
/* if (!(ret % 6)) */
/* puts(""); */
/* printf("%.2X ", rx[ret]); */
/* } */
/* puts(""); */
double temp = ((ad_data.data[0]/16.0)*3.3*1000/(1 << 10)-600)/10.0;
printf ("%lf\n", temp);
}