Files
HendiControlFirmware/Control/firmware/uart_echo/main.c
T
jens 36c8bf481a - cleaned up
- add MCP47x6 code

git-svn-id: http://moon:8086/svn/projects/HendiControl@14 fda53097-d464-4ada-af97-ba876c37ca34
2019-02-18 20:43:41 +00:00

437 lines
8.5 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 <stdlib.h>
#include <string.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 38400UL
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
#define TIMER_RELOAD (0xFFFF-(F_CPU/1024/4-1))
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
};
typedef struct _sMsg_t
{
uint8_t code;
uint8_t data;
} Msg_t;
typedef struct _sFifo
{
void **ppData;
size_t capacity;
size_t itemSize;
size_t fill;
size_t wi;
size_t ri;
const char *pName;
} Fifo;
static Fifo messageFifo;
void Fifo_init(Fifo *pObj, size_t capacity, size_t itemSize, const char *pName)
{
pObj->wi = 0;
pObj->ri = 0;
pObj->fill = 0;
pObj->capacity = capacity;
pObj->itemSize = itemSize;
pObj->ppData = (void**)malloc(capacity);
for (int i=0; i < capacity; i++)
{
pObj->ppData[i] = (void*)malloc(itemSize);
}
pObj->pName = pName;
}
void Fifo_free(Fifo *pObj)
{
for (int i=0; i < pObj->capacity; i++)
{
free(pObj->ppData[i]);
}
free (pObj->ppData);
pObj->itemSize = 0;
pObj->capacity = 0;
}
void Fifo_push(Fifo *pObj, void *pItem)
{
if (pObj->fill >= pObj->capacity)
{
printf("%s: Fifo is full\n", pObj->pName);
return;
}
memcpy(pObj->ppData[pObj->wi], pItem, pObj->itemSize);
pObj->wi++;
pObj->fill++;
if (pObj->wi == pObj->capacity)
{
pObj->wi = 0;
}
}
int Fifo_pop(Fifo *pObj, void *pItem)
{
if (!pObj->fill)
{
return 0;
}
memcpy(pItem, pObj->ppData[pObj->ri], pObj->itemSize);
pObj->ri++;
pObj->fill--;
if (pObj->ri == pObj->capacity)
{
pObj->ri = 0;
}
return 1;
}
int Fifo_isEmpty(Fifo *pObj)
{
return pObj->fill == 0;
}
void adc_start_conversion(int ch);
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))
{
Msg_t msg = {AdcComplete, adc_ch};
Fifo_push(&messageFifo, &msg);
}
adc_value[adc_ch] = value;
adc_ch++;
if (adc_ch == 16)
{
adc_ch = 0;
}
adc_start_conversion(adc_ch);
}
ISR(USART_RX_vect)
{
uint8_t rx_data = UDR0;
if (rx_data == ' ')
{
Msg_t msg = {Error, rx_data};
Fifo_push(&messageFifo, &msg);
}
else if (rx_data >= '0' && rx_data <= '9')
{
Msg_t msg = {Command, rx_data};
Fifo_push(&messageFifo, &msg);
}
}
ISR (TIMER1_OVF_vect) // Timer1 ISR
{
Msg_t msg = {Timer, ledState};
Fifo_push(&messageFifo, &msg);
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 = 0x00;
}
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)));
}
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);
enum MCP47x6_flags
{
C0 = 0x20,
C1 = 0x40,
C2 = 0x80,
PDN0 = 0x10,
PDN1 = 0x20,
mask = 0xF0
};
size_t MCP47x6_write_volatile_dac(uint16_t dac_value, uint8_t *buffer, size_t size)
{
*(buffer++) = ~mask & (uint8_t)(dac_value >> 8);
*(buffer++) = (uint8_t)(dac_value >> 0);
return 2;
}
size_t MCP47x6_write_volatile_mem(uint16_t dac_value, uint8_t *buffer, size_t size)
{
*(buffer++) = mask & 0x40;
dac_value <<= 4;
*(buffer++) = (uint8_t)(dac_value >> 8);
*(buffer++) = (uint8_t)(dac_value >> 0);
return 3;
}
int main(void)
{
Fifo_init(&messageFifo, 64, sizeof(Msg_t), "Fifo");
/* 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 dac_cmd[] = {0x00, 0x00, 0x00}; // 6.1 Write Volatile DAC Register (C2:C0 = 00x)
size_t res = MCP47x6_write_volatile_mem(0x0000, dac_cmd, sizeof(dac_cmd));
i2c_send(0x60, I2C_WRITE, dac_cmd, res);
sei();
adc_start_conversion(adc_ch);
while (1)
{
Msg_t msg;
if (!Fifo_isEmpty(&messageFifo))
{
cli();
Fifo_pop(&messageFifo, &msg);
sei();
switch(msg.code)
{
case Command:
{
printf("Command : %c\n", msg.data);
uint8_t dac_cmd[] = {0x00, 0x00}; // 6.2 Write Volatile Memory (C2:C0 = 010)
size_t res = MCP47x6_write_volatile_dac((uint16_t)(msg.data-'0')<<8, dac_cmd, sizeof(dac_cmd));
i2c_send(0x60, I2C_WRITE, dac_cmd, res);
}
break;
case AdcComplete:
{
size_t ch = msg.data;
if (ch == 6)
{
printf("ADC=%d\n", adc_value[ch]);
uint8_t dac_cmd[] = {0x00, 0x00}; // 6.2 Write Volatile Memory (C2:C0 = 010)
size_t res = MCP47x6_write_volatile_dac(adc_value[ch]<<2, dac_cmd, sizeof(dac_cmd));
i2c_send(0x60, I2C_WRITE, dac_cmd, res);
}
}
break;
case Timer:
switch(msg.data)
{
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;
}
}
}
}