/***************************************************************************** * * FILENAME: main.c * COMPILER: WIN-AVR * PROCESSOR: ATTINY2313 * * COMPANY,DPT,AUTHOR: Home, Alen Harbas * * DATE OF CREATION: 17.07.2016 * *****************************************************************************/#include "stdio.h"
#ifndef F_CPU#define F_CPU 8000000UL#endif
#define GREEN_LED PORT4#define WATER_SENSOR PD2#define WATER_SENSOR_PIN PIND
#define BAUD 9600#define MYUBBR ((F_CPU / (BAUD * 16L)) - 1)
#define USI_OUT_REG PORTB //!< USI port output register.#define USI_IN_REG PINB //!< USI port input register.#define USI_DIR_REG DDRB //!< USI port direction register.#define USI_CLOCK_PIN PB7 //!< USI clock I/O pin.
#define USI_DATAIN_PIN PB5 //!< USI data input pin. MOSI#define USI_DATAOUT_PIN PB6 //!< USI data output pin. MISO
#define USI_SS_PIN PB4
#define SPI_SELECT USI_OUT_REG &= ~(1 << USI_SS_PIN)#define SPI_DESELECT USI_OUT_REG|= (1 << USI_SS_PIN)
/** \name SPI Kommandos *//*@{*/#define SPI_RESET 0xC0#define SPI_READ 0x03#define SPI_READ_RX 0x90#define SPI_WRITE 0x02#define SPI_WRITE_TX 0x40#define SPI_RTS 0x80#define SPI_READ_STATUS 0xA0#define SPI_RX_STATUS 0xB0#define SPI_BIT_MODIFY 0x05
/*@}*/
/** \name Adressen der Register des MCP2515 * * Die Redundanten Adressen von z.B. dem Register CANSTAT * (0x0E, 0x1E, 0x2E, ...) wurden dabei nicht mit aufgelistet. *//*@{*/#define RXF0SIDH 0x00#define RXF0SIDL 0x01#define RXF0EID8 0x02#define RXF0EID0 0x03#define RXF1SIDH 0x04#define RXF1SIDL 0x05#define RXF1EID8 0x06#define RXF1EID0 0x07#define RXF2SIDH 0x08#define RXF2SIDL 0x09#define RXF2EID8 0x0A#define RXF2EID0 0x0B#define BFPCTRL 0x0C#define TXRTSCTRL 0x0D#define CANSTAT 0x0E#define CANCTRL 0x0F
#define RXF3SIDH 0x10#define RXF3SIDL 0x11#define RXF3EID8 0x12#define RXF3EID0 0x13#define RXF4SIDH 0x14#define RXF4SIDL 0x15#define RXF4EID8 0x16#define RXF4EID0 0x17#define RXF5SIDH 0x18#define RXF5SIDL 0x19#define RXF5EID8 0x1A#define RXF5EID0 0x1B#define TEC 0x1C#define REC 0x1D
#define RXM0SIDH 0x20#define RXM0SIDL 0x21#define RXM0EID8 0x22#define RXM0EID0 0x23#define RXM1SIDH 0x24#define RXM1SIDL 0x25#define RXM1EID8 0x26#define RXM1EID0 0x27#define CNF3 0x28#define CNF2 0x29#define CNF1 0x2A#define CANINTE 0x2B#define CANINTF 0x2C#define EFLG 0x2D
#define TXB0CTRL 0x30#define TXB0SIDH 0x31#define TXB0SIDL 0x32#define TXB0EID8 0x33#define TXB0EID0 0x34#define TXB0DLC 0x35#define TXB0D0 0x36#define TXB0D1 0x37#define TXB0D2 0x38#define TXB0D3 0x39#define TXB0D4 0x3A#define TXB0D5 0x3B#define TXB0D6 0x3C#define TXB0D7 0x3D
#define TXB1CTRL 0x40#define TXB1SIDH 0x41#define TXB1SIDL 0x42#define TXB1EID8 0x43#define TXB1EID0 0x44#define TXB1DLC 0x45#define TXB1D0 0x46#define TXB1D1 0x47#define TXB1D2 0x48#define TXB1D3 0x49#define TXB1D4 0x4A#define TXB1D5 0x4B#define TXB1D6 0x4C#define TXB1D7 0x4D
#define TXB2CTRL 0x50#define TXB2SIDH 0x51#define TXB2SIDL 0x52#define TXB2EID8 0x53#define TXB2EID0 0x54#define TXB2DLC 0x55#define TXB2D0 0x56#define TXB2D1 0x57#define TXB2D2 0x58#define TXB2D3 0x59#define TXB2D4 0x5A#define TXB2D5 0x5B#define TXB2D6 0x5C#define TXB2D7 0x5D
#define RXB0CTRL 0x60#define RXB0SIDH 0x61#define RXB0SIDL 0x62#define RXB0EID8 0x63#define RXB0EID0 0x64#define RXB0DLC 0x65#define RXB0D0 0x66#define RXB0D1 0x67#define RXB0D2 0x68#define RXB0D3 0x69#define RXB0D4 0x6A#define RXB0D5 0x6B#define RXB0D6 0x6C#define RXB0D7 0x6D
#define RXB1CTRL 0x70#define RXB1SIDH 0x71#define RXB1SIDL 0x72#define RXB1EID8 0x73#define RXB1EID0 0x74#define RXB1DLC 0x75#define RXB1D0 0x76#define RXB1D1 0x77#define RXB1D2 0x78#define RXB1D3 0x79#define RXB1D4 0x7A#define RXB1D5 0x7B#define RXB1D6 0x7C#define RXB1D7 0x7D/*@}*/
/** \name Bitdefinition der verschiedenen Register *//*@{*/
/** \brief Bitdefinition von BFPCTRL */#define B1BFS 5#define B0BFS 4#define B1BFE 3#define B0BFE 2#define B1BFM 1#define B0BFM 0
/** \brief Bitdefinition von TXRTSCTRL */#define B2RTS 5#define B1RTS 4#define B0RTS 3#define B2RTSM 2#define B1RTSM 1#define B0RTSM 0
/** \brief Bitdefinition von CANSTAT */#define OPMOD2 7#define OPMOD1 6#define OPMOD0 5#define ICOD2 3#define ICOD1 2#define ICOD0 1
/** \brief Bitdefinition von CANCTRL */#define REQOP2 7#define REQOP1 6#define REQOP0 5#define ABAT 4#define CLKEN 2#define CLKPRE1 1#define CLKPRE0 0
/** \brief Bitdefinition von CNF3 */#define WAKFIL 6#define PHSEG22 2#define PHSEG21 1#define PHSEG20 0
/** \brief Bitdefinition von CNF2 */#define BTLMODE 7#define SAM 6#define PHSEG12 5#define PHSEG11 4#define PHSEG10 3#define PHSEG2 2#define PHSEG1 1#define PHSEG0 0
/** \brief Bitdefinition von CNF1 */#define SJW1 7#define SJW0 6#define BRP5 5#define BRP4 4#define BRP3 3#define BRP2 2#define BRP1 1#define BRP0 0
/** \brief Bitdefinition von CANINTE */#define MERRE 7#define WAKIE 6#define ERRIE 5#define TX2IE 4#define TX1IE 3#define TX0IE 2#define RX1IE 1#define RX0IE 0
/** \brief Bitdefinition von CANINTF */#define MERRF 7#define WAKIF 6#define ERRIF 5#define TX2IF 4#define TX1IF 3#define TX0IF 2#define RX1IF 1#define RX0IF 0
/** \brief Bitdefinition von EFLG */#define RX1OVR 7#define RX0OVR 6#define TXB0 5#define TXEP 4#define RXEP 3#define TXWAR 2#define RXWAR 1#define EWARN 0
/** \brief Bitdefinition von TXBnCTRL (n = 0, 1, 2) */#define ABTF 6#define MLOA 5#define TXERR 4#define TXREQ 3#define TXP1 1#define TXP0 0
/** \brief Bitdefinition von RXB0CTRL */#define RXM1 6#define RXM0 5#define RXRTR 3#define BUKT 2#define BUKT1 1#define FILHIT0 0
/** \brief Bitdefinition von TXBnSIDL (n = 0, 1) */#define EXIDE 3
/** * \brief Bitdefinition von RXB1CTRL * \see RXM1, RXM0, RXRTR und FILHIT0 sind schon fuer RXB0CTRL definiert */#define FILHIT2 2#define FILHIT1 1
/** \brief Bitdefinition von RXBnSIDL (n = 0, 1) */#define SRR 4#define IDE 3
/** * \brief Bitdefinition von RXBnDLC (n = 0, 1) * \see TXBnDLC (gleiche Bits) */#define RTR 6#define DLC3 3#define DLC2 2#define DLC1 1#define DLC0 0
/* ========== Includes ===================================================== */
#include <avr/io.h>#include <util/delay.h>#include <avr/interrupt.h>
/* ========== Enumerations, Typedefinitions, Local Defines ================= */
typedef struct{ uint16_t id; struct { int8_t rtr : 1; uint8_t length : 4; } header; uint8_t data[8];} CANMessage;
/* ========== Local function prototypes ==================================== */
static void LEDInit(void);static void UARTSend(uint8_t c);static void UARTInit(void);
static void SPIInit(void);static uint8_t SPIWrite(uint8_t data);static void MCP2515WriteRegister( uint8_t adress, uint8_t data );static uint8_t MCP2515ReadRegister(uint8_t adress);static void MCP2515ModifyBit(uint8_t adress, uint8_t mask, uint8_t data);static void MCP2515Init(void);static uint8_t MCP2515SendMessage(CANMessage *p_message);static uint8_t MCP2515ReadRxStatus(void);static uint8_t MCP2515GetMessage(CANMessage *p_message);
/* ========== Local variables ============================================== */
/* ========== Macros ======================================================= */
/* ========== Functions ==================================================== */
int printCHAR(char character, FILE *stream){ UARTSend(character); return 0;}
FILE uart_str = FDEV_SETUP_STREAM(printCHAR, NULL, _FDEV_SETUP_RW);
/***************************************************************************** * FUNCTION: void main(...) *****************************************************************************/int main (void){
int switch_led = 0;
_delay_ms(1000); LEDInit(); MCP2515Init(); UARTInit();
sei(); // Enable INTs
UARTSend('C'); UARTSend('A'); UARTSend('N'); UARTSend('\r'); UARTSend('\n');
stdout = &uart_str; printf("Hello World 2\n\r");
while(1){
}//end of while return 0;}/***************************************************************************** * FUNCTION: void LEDInit(void) *****************************************************************************/void LEDInit(void){
DDRD |= (1<<DDD4); DDRB &= ~(1<<PB1);}/***************************************************************************** * FUNCTION: void UARTInit() *****************************************************************************/void UARTInit( void ) { // set baud rate UBRRH = (uint8_t)(MYUBBR >> 8); UBRRL = (uint8_t)(MYUBBR); // enable receive and transmit UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE); // set frame format UCSRC = (1 << USBS) | (3 << UCSZ0); // asynchron 8n1}/***************************************************************************** * FUNCTION: void UARTSend() *****************************************************************************/void UARTSend(uint8_t c) { // wait for empty data register while (!(UCSRA & (1<<UDRE))); // set data into data register UDR = c;}/***************************************************************************** * FUNCTION: void ISR(USART_UDRE_vect) *****************************************************************************/ISR(USART_UDRE_vect) { UDR = PINB;}/***************************************************************************** * FUNCTION: void ISR(INT1_vect) *****************************************************************************/ISR(INT1_vect){ CANMessage ret_message; ret_message.id = 0; ret_message.header.length = 0; MCP2515GetMessage(&ret_message); if(ret_message.id == 0x16){ PORTD |= (1<<GREEN_LED); _delay_ms(1000); PORTD &= ~(1<<GREEN_LED); } UARTSend('m'); UARTSend('s'); UARTSend('g'); UARTSend(':'); for(int c = 0; c < ret_message.header.length; c++){ UARTSend(ret_message.data[c]); } UARTSend('\r'); UARTSend('\n');
}/***************************************************************************** * FUNCTION: void SPIinit(void) *****************************************************************************/void SPIInit(void){
//SPI USI_DIR_REG |= (1<<USI_DATAOUT_PIN); // as output (DO) USI_DIR_REG |= (1<<USI_CLOCK_PIN); // as output (USISCK) USI_DIR_REG |= (1<<USI_SS_PIN); // as output (SS)
USI_DIR_REG &= ~(1<<USI_DATAIN_PIN); // as input (DI) USI_OUT_REG |= (1<<USI_SS_PIN) | (1<<USI_DATAIN_PIN); // pullup on (DI)
//disable overflow interrupt //Set to three wire mode //Positive edge shift register clock //Strobe the shift register to shift one step and increment counter USICR = (0<<USIOIE) | (1<<USIWM0) | (1<<USICS1) | (1<<USICLK);
}/***************************************************************************** * FUNCTION: void SPIWrite(data) *****************************************************************************/uint8_t SPIWrite(uint8_t data){
/* USIDR = data; for(uint8_t i=0; i < 8; i++){ USICR = (1<< USIWM0) | (1 << USITC); // toggle the clock //USICLK which shifts or clocks out bits to DO USICR = (1<< USIWM0) | (1 << USITC) | (1 << USICLK); // toggle clk pin and DO pin }*/
//Load data into data register USIDR = data; //Clear the USI counter overflow flag and USI counter value. USISR = (1<<USIOIF); //USIOIF will be set when all 8 bits are transferred do { //Toggle clock port pin USICR |= (0<<USIOIE) | (1<<USIWM0) | (1<<USICS1) | (1<<USICLK) | (1<<USITC); } while((USISR & (1<<USIOIF)) == 0); return USIDR; }
/***************************************************************************** * FUNCTION: *****************************************************************************/void MCP2515WriteRegister( uint8_t adress, uint8_t data ){ SPI_SELECT; SPIWrite(SPI_WRITE); SPIWrite(adress); SPIWrite(data); SPI_DESELECT;}/***************************************************************************** * FUNCTION: *****************************************************************************/uint8_t MCP2515ReadRegister(uint8_t adress){ uint8_t data; SPI_SELECT; SPIWrite(SPI_READ); SPIWrite(adress); data = SPIWrite(0xff); SPI_DESELECT; return data;}/***************************************************************************** * FUNCTION: *****************************************************************************/void MCP2515ModifyBit(uint8_t adress, uint8_t mask, uint8_t data){ SPI_SELECT; SPIWrite(SPI_BIT_MODIFY); SPIWrite(adress); SPIWrite(mask); SPIWrite(data);
SPI_DESELECT;}/***************************************************************************** * FUNCTION: *****************************************************************************/void MCP2515Init(void){
SPIInit(); SPI_SELECT;
SPIWrite( SPI_RESET ); _delay_ms(1); SPI_DESELECT; // etwas warten bis sich der MCP2515 zurueckgesetzt hat _delay_ms(10);
// RX0BF als Digitalen Ausgang nutzen uint8_t data = (1<<B0BFE) | (1<<B0BFS); MCP2515ModifyBit( BFPCTRL, (1<<B0BFE) | (1<<B0BFM) | (1<<B0BFS), data); // set clock out to 8MHz MCP2515ModifyBit( CANCTRL, (1<<CLKEN) | (1<<CLKPRE0) | (1<<CLKPRE1), (1<<CLKEN));
//https://www.kvaser.com/support/calculators/bit-timing-calculator/
//250 gigatronik //MCP2515WriteRegister( CNF1, 0x00 ); // Prop Seg und Phase Seg1 einstellen //MCP2515WriteRegister( CNF2, 0x9A ); // Wake-up Filter deaktivieren, Phase Seg2 einstellen //MCP2515WriteRegister( CNF3, 0x07 );
//125 MCP2515WriteRegister( CNF1, 0x01 ); // Prop Seg und Phase Seg1 einstellen MCP2515WriteRegister( CNF2, 0xAC ); // Wake-up Filter deaktivieren, Phase Seg2 einstellen MCP2515WriteRegister( CNF3, 0x03 );
// Aktivieren der Rx Buffer Interrupts MCP2515WriteRegister( CANINTE, (1<<RX1IE)|(1<<RX0IE) );
// deaktivate the RXnBF Pins (High Impedance State) //MCP2515WriteRegister(BFPCTRL, 0); // set TXnRTS as inputs //MCP2515WriteRegister(TXRTSCTRL, 0); // turn off filters => receive any message MCP2515WriteRegister(RXB0CTRL, (1<<RXM1)|(1<<RXM0)); MCP2515WriteRegister(RXB1CTRL, (1<<RXM1)|(1<<RXM0));
// Alle Bits der Empfangsmaske loeschen, // damit werden alle Nachrichten empfangen MCP2515WriteRegister( RXM0SIDH, 0 ); MCP2515WriteRegister( RXM0SIDL, 0 ); MCP2515WriteRegister( RXM0EID8, 0 ); MCP2515WriteRegister( RXM0EID0, 0 ); MCP2515WriteRegister( RXM1SIDH, 0 ); MCP2515WriteRegister( RXM1SIDL, 0 ); MCP2515WriteRegister( RXM1EID8, 0 ); MCP2515WriteRegister( RXM1EID0, 0 ); // reset device to normal mode MCP2515WriteRegister(CANCTRL, 0); return;
}/***************************************************************************** * FUNCTION: *****************************************************************************/uint8_t MCP2515SendMessage(CANMessage *p_message){ uint8_t address; uint8_t status = MCP2515ReadRxStatus(); /* Statusbyte: * * Bit Funktion * 2 TXB0CNTRL.TXREQ * 4 TXB1CNTRL.TXREQ * 6 TXB2CNTRL.TXREQ */ if (bit_is_clear(status, 2)) { address = 0x00; } else if (bit_is_clear(status, 4)) { address = 0x02; } else if (bit_is_clear(status, 6)) { address = 0x04; } else { /* Alle Puffer sind belegt, Nachricht kann nicht verschickt werden */ return 0; } SPI_SELECT; // CS Low SPIWrite(SPI_WRITE_TX | address); // Standard ID einstellen SPIWrite((uint8_t) (p_message->id>>3)); SPIWrite((uint8_t) (p_message->id<<5)); // Extended ID SPIWrite(0x00); SPIWrite(0x00); uint8_t length = p_message->header.length & 0x0f; if (length > 8) { length = 8; } // Ist die Nachricht ein "Remote Transmit Request" ? if (p_message->header.rtr) { /* Ein RTR hat zwar eine Laenge, aber enthaelt keine Daten */ // Nachrichten Laenge + RTR einstellen SPIWrite((1<<RTR) | length); } else { // Nachrichten Laenge einstellen SPIWrite(length); // Daten for (uint8_t i=0;i<length;i++) { SPIWrite(p_message->data[i]); } } SPI_DESELECT; // CS auf High asm volatile ("nop"); /* CAN Nachricht verschicken die letzten drei Bit im RTS Kommando geben an welcher Puffer gesendet werden soll */ SPI_SELECT; // CS wieder Low if (address == 0x00) { SPIWrite(SPI_RTS | 0x01); } else { SPIWrite(SPI_RTS | address); } SPI_DESELECT; // CS auf High return 1;}/***************************************************************************** * FUNCTION: *****************************************************************************/uint8_t MCP2515ReadRxStatus(void){ uint8_t data; // /CS des MCP2515 auf Low ziehen SPI_SELECT; SPIWrite(SPI_RX_STATUS); data = SPIWrite(0xff); // Die Daten werden noch einmal wiederholt gesendet, // man braucht also nur eins der beiden Bytes auswerten. SPIWrite(0xff); // /CS Leitung wieder freigeben SPI_DESELECT; return data;}/***************************************************************************** * FUNCTION: *****************************************************************************/uint8_t MCP2515GetMessage(CANMessage *p_message){ // Status auslesen uint8_t status = MCP2515ReadRxStatus(); uint8_t addr; if (bit_is_set(status,6)) { // message in buffer 0 addr = SPI_READ_RX; } else if (bit_is_set(status,7)) { // message in buffer 1 addr = SPI_READ_RX | 0x04; } else { /* Fehler: Keine neue Nachricht vorhanden */ return 0xff; } SPI_SELECT; SPIWrite(addr); // read id p_message->id = (uint16_t) SPIWrite(0xff) << 3; p_message->id |= SPIWrite(0xff) >> 5; SPIWrite(0xff); SPIWrite(0xff); // read DLC uint8_t length = SPIWrite(0xff) & 0x0f; p_message->header.length = length; p_message->header.rtr = (bit_is_set(status, 3)) ? 1 : 0; // Daten auslesen for (uint8_t i=0;i<length;i++) { p_message->data[i] = SPIWrite(0xff); } SPI_DESELECT; if (bit_is_set(status,3)) { p_message->header.rtr = 1; } else { p_message->header.rtr = 0; } // Interrupt Flag loeschen if (bit_is_set(status,6)) { MCP2515ModifyBit(CANINTF, (1<<RX0IF), 0); } else { MCP2515ModifyBit(CANINTF, (1<<RX1IF), 0); } return (status & 0x07) + 1;}