Files
HendiControlFirmware/Control/firmware/uart_echo/main.c
T
jens 15df3f87ab - added I2C DAC
git-svn-id: http://moon:8086/svn/projects/HendiControl@11 fda53097-d464-4ada-af97-ba876c37ca34
2019-02-14 22:18:55 +00:00

332 lines
6.3 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* uart_echo.c
*
* Created: 16.08.2018 17:39:49
* Author : jens
*/
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define ARDUINO_NANO
#ifdef ARDUINO_NANO
#define F_CPU (16000000UL) // MHz
#else
#define F_CPU (18432000UL) // MHz
#endif
#define USART_BAUDRATE 9600UL
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
#define TIMER_RELOAD (0xFFFF-(F_CPU/1024/4-1))
static uint8_t rx_data;
static uint8_t count = 0;
volatile uint8_t msgCode = 0;
static uint8_t msgData = 0;
static uint8_t ledState = 0;
static int16_t adc_value[16];
static size_t adc_ch = 0;
enum MessageCode
{
NOP=0,
Command,
Timer,
AdcComplete,
Error = 0xFF
};
ISR(ADC_vect)
{
int16_t value_low = (int16_t)ADCL;
int16_t value_high = (int16_t)ADCH;
ADCSRA |= (1<<ADIF);
int16_t value = value_high << 8 | value_low;
if (((adc_value[adc_ch] - value) < -1) || ((adc_value[adc_ch] - value) > 1))
{
msgCode = AdcComplete;
msgData = adc_ch;
}
adc_value[adc_ch] = value;
adc_ch++;
if (adc_ch == 16)
{
adc_ch = 0;
}
adc_start_conversion(adc_ch);
}
ISR(USART_RX_vect)
{
rx_data = UDR0;
msgCode = NOP;
if (rx_data == ' ')
{
msgCode = Error;
}
else if (rx_data >= '0' && rx_data <= '9')
{
msgCode = Command;
msgData = rx_data;
}
count++;
}
ISR (TIMER1_OVF_vect) // Timer1 ISR
{
msgCode = Timer;
TCNT1 = TIMER_RELOAD;
ledState++;
if (ledState == 4)
{
ledState = 0;
}
}
void uart_init()
{
// Set baud rate
UBRR0L = (uint8_t)BAUD_PRESCALE;
UBRR0H = (uint8_t)(BAUD_PRESCALE >> 8);
// Enable receiver and transmitter
UCSR0B = (1<<TXEN0)|(1<<RXEN0);
// Enable RX interrupt
UCSR0B |= (1<<RXCIE0);
}
void timer_init()
{
TCNT1 = TIMER_RELOAD;
TCCR1A = 0x00;
TCCR1B = (1<<CS10) | (1<<CS12); // Timer mode with 1024 prescaler
TIMSK1 = (1 << TOIE1) ; // Enable timer1 overflow interrupt(TOIE1)
}
enum I2C
{
I2C_START = 0x08,
I2C_REPEATED_START = 0x10,
I2C_SLA_ACK = 0x18,
I2C_SLA_NACK = 0x20,
I2C_DATA_ACK = 0x28,
I2C_DATA_NACK = 0x30,
I2C_LOST = 0x38,
I2C_READ = 0x01,
I2C_WRITE = 0x00
};
void i2c_init()
{
TWBR = 0xFF;
TWSR = 0x03;
}
void i2c_send(uint8_t addr, uint8_t rw, uint8_t *data, size_t size)
{
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
// Send START condition
do
{
while (!(TWCR &(1<<TWINT))); // Wait for TWINT Flag set. This indicates
// that the START condition has been
// transmitted.
if((TWSR & 0xF8) != I2C_START)
{
printf("Error I2C_START\n");
break;
}
TWDR = addr<<1 | rw; // Load SLA_W into TWDR Register. Clear
// TWINT bit in TWCR to start transmission of
// address.
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR &(1<<TWINT))); // Wait for TWINT Flag set. This indicates
// that the SLA+W has been transmitted, and
// ACK/NACK has been received.
if ((TWSR & 0xF8) != I2C_SLA_ACK)
{
printf("Error I2C_SLA_ACK\n");
break;
}
// Check value of TWI Status Register. Mask
// prescaler bits. If status different from
// MT_SLA_ACK go to ERROR
for (size_t i=0; i < size; i++)
{
TWDR = *(data++);
TWCR = (1<<TWINT) | (1<<TWEN);
// Load DATA into TWDR Register. Clear
// TWINT bit in TWCR to start transmission of
// data.
while (!(TWCR & (1<<TWINT)));
// Wait for TWINT Flag set. This indicates
// that the DATA has been transmitted, and
// ACK/NACK has been received}
if ((TWSR & 0xF8) != I2C_DATA_ACK)
{
printf("Error I2C_DATA_ACK\n");
break;
}
// Check value of TWI Status Register. Mask
// prescaler bits. If status different from
// MT_DATA_ACK go to ERROR.
}
} while (0);
TWCR = (1<<TWINT)| (1<<TWEN)|(1<<TWSTO); // Transmit STOP condition.
}
void adc_init()
{
PRR &= ~(1 << PRADC);
ADCSRA |= (1 << ADEN) | 7;
}
void adc_start_conversion(int ch)
{
ADMUX = (ADMUX & 0xF0) | (ch & 0x0F) | (1 << REFS0);
ADCSRA |= (1 << ADSC) | (1 << ADIE);
}
int adc_is_fininshed()
{
return (int)(0 == (ADCSRA & (1 << ADSC)));
}
int16_t adc_read()
{
return adc_value;
while(!adc_is_fininshed());
uint16_t value_low = (uint16_t)ADCL;
uint16_t value_high = (uint16_t)ADCH;
ADCSRA |= (1<<ADIF);
return value_high << 8 | value_low;
}
void uart_putc(char c)
{
while((UCSR0A & (1<<UDRE0)) == 0)
{
}
UDR0 = c;
}
int uart_putchar(char c, FILE *stream)
{
uart_putc(c);
if (c == 0x0A)
{
uart_putc(0x0D);
}
return 0;
}
void uart_puts(char const *str)
{
while(*str)
{
char c = *(str++);
uart_putc(c);
if (c == 0x0A)
{
uart_putc(0x0D);
}
}
}
void port_init()
{
PORTB = PORTB | 0x03;
DDRB = DDB1 | DDB2;
}
FILE uart_file = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
int main(void)
{
/* Replace with your application code */
uart_init();
timer_init();
adc_init();
i2c_init();
stdout = &uart_file;
printf("UART test version 1.0\n\n");
uint8_t write_dac_full[] = {0x40, 0x00, 0x00}; // 6.1 Write Volatile DAC Register (C2:C0 = 00x)
i2c_send(0x60, I2C_WRITE, write_dac_full, sizeof(write_dac_full));
sei();
adc_start_conversion(adc_ch);
while (1)
{
if (msgCode)
{
cli();
uint8_t _msgCode = msgCode;
uint8_t _msgData = msgData;
sei();
switch(_msgCode)
{
case Command:
printf("Command : %c\n", _msgData);
uint8_t write_dac[] = {0x00+(_msgData-'0'), 0x00}; // 6.2 Write Volatile Memory (C2:C0 = 010)
i2c_send(0x60, I2C_WRITE, write_dac, sizeof(write_dac));
break;
case AdcComplete:
{
size_t ch = _msgData;
if (ch == 6)
{
printf("ADC=%d\n", adc_value[ch]);
}
}
break;
case Timer:
switch(ledState)
{
case 0:
DDRB = (DDRB & 0xFC) | 0x00;
printf("----------- Timer -----------\n");
break;
case 1:
DDRB = (DDRB & 0xFC) | 0x01;
break;
case 2:
DDRB = (DDRB & 0xFC) | 0x03;
break;
case 3:
DDRB = (DDRB & 0xFC) | 0x02;
break;
}
break;
case Error:
printf("Error!!!\n");
break;
}
}
}
}