From e7d765ea907dada5d42735a43ccf0b45080789c1 Mon Sep 17 00:00:00 2001 From: Piotr Esden-Tempski Date: Sat, 25 Dec 2010 20:39:46 +0100 Subject: [PATCH] Factored out CAN helper functions out of the example. Test code now also uses the received data. --- examples/obldc/can/can.c | 197 ++++++++----------- include/libopenstm32/can.h | 45 ++++- include/libopenstm32/common.h | 1 + lib/Makefile | 2 +- lib/can.c | 352 ++++++++++++++++++++++++++++++++++ 5 files changed, 470 insertions(+), 127 deletions(-) create mode 100644 lib/can.c diff --git a/examples/obldc/can/can.c b/examples/obldc/can/can.c index d81eeb95..bc5f23f6 100644 --- a/examples/obldc/can/can.c +++ b/examples/obldc/can/can.c @@ -88,8 +88,6 @@ void systick_setup() void can_setup() { - u32 wait_ack = 0x00000000; - u32 can_msr_inak_timeout = 0x000FFFFF; /* Enable peripheral clocks */ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_AFIOEN); @@ -109,156 +107,111 @@ void can_setup() nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ); nvic_set_priority(NVIC_USB_LP_CAN_RX0_IRQ, 1); - /* --- reset CAN periphery ------------------------------------------ */ + /* reset CAN */ + can_reset(CAN1); - rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CANRST); - rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CANRST); + /* CAN cell init */ + if (can_init(CAN1, + false, /* TTCM: Time triggered comm mode? */ + true, /* ABOM: Automatic bus-off management? */ + false, /* AWUM: Automatic wakeup mode? */ + false, /* NART: No automatic retransmission? */ + false, /* RFLM: Receive FIFO locked mode? */ + false, /* TXFP: Transmit FIFO priority? */ + CAN_BTR_SJW_1TQ, + CAN_BTR_TS1_3TQ, + CAN_BTR_TS2_4TQ, + 12)) { /* BRP+1: Baud rate prescaler */ - /* --- CAN cell init ------------------------------------------------ */ + gpio_set(GPIOA, GPIO6); /* LED0 off */ + gpio_set(GPIOA, GPIO7); /* LED1 off */ + gpio_set(GPIOB, GPIO0); /* LED2 off */ + gpio_clear(GPIOB, GPIO1); /* LED3 on */ - /* Exit from sleep mode */ - CAN_MCR(CAN1) &= ~CAN_MCR_SLEEP; - - /* Request initialization "enter" */ - CAN_MCR(CAN1) |= CAN_MCR_INRQ; - - /* Wait for acknowledge */ - while ((wait_ack != can_msr_inak_timeout) && - ((CAN_MSR(CAN1) & CAN_MSR_INAK) != CAN_MSR_INAK)) { - wait_ack++; - } - - /* Check the acknowledge */ - if ((CAN_MSR(CAN1) & CAN_MSR_INAK) != CAN_MSR_INAK) { - /* we should set some flag here or so because we failed */ - gpio_clear(GPIOB, GPIO1); - } else { - - /* set the automatic bus-off management */ - CAN_MCR(CAN1) &= ~CAN_MCR_TTCM; - CAN_MCR(CAN1) |= CAN_MCR_ABOM; - CAN_MCR(CAN1) &= ~CAN_MCR_AWUM; - CAN_MCR(CAN1) &= ~CAN_MCR_NART; - CAN_MCR(CAN1) &= ~CAN_MCR_TXFP; - - /* Set bit timings */ - CAN_BTR(CAN1) = 0x00000000 | - CAN_BTR_SJW_1TQ | - CAN_BTR_TS2_4TQ | - CAN_BTR_TS1_3TQ | - (u32)(CAN_BTR_BRP_MASK & (12 - 1)); - - /* Request initialization "leave" */ - CAN_MCR(CAN1) &= ~CAN_MCR_INRQ; - - /* Wait for acknowledge */ - wait_ack = 0x00000000; - while ((wait_ack != can_msr_inak_timeout) && - ((CAN_MSR(CAN1) & CAN_MSR_INAK) == CAN_MSR_INAK)) { - wait_ack++; - } - - if ((CAN_MSR(CAN1) & CAN_MSR_INAK) == CAN_MSR_INAK) { - /* set some flag here because we failed */ - gpio_clear(GPIOB, GPIO1); - } else { - /* set some flag here because we succeeded */ - gpio_set(GPIOB, GPIO1); + /* die because we failed to initialize */ + while(1){ + __asm("nop"); } } /* --- CAN filter 0 init -------------------------------------------- */ - u32 filter_select_bit = 0x00000001; - - /* Request initialization "enter" */ - CAN_FMR(CAN1) |= CAN_FMR_FINIT; - - /* Deactivate the filter */ - CAN_FA1R(CAN1) &= ~filter_select_bit; - - /* Set 32-bit scale for the filter */ - CAN_FS1R(CAN1) |= filter_select_bit; - - /* Set the filter id to 0 */ - CAN_FiR1(CAN1, 0) = 0x00000000; - - /* Set the filter id mask to 0 */ - CAN_FiR2(CAN1, 0) = 0x00000000; - - /* Set filter mode to Id/Mask mode */ - CAN_FM1R(CAN1) &= ~filter_select_bit; - - /* Select FIFO0 as filter assignement */ - CAN_FFA1R(CAN1) &= ~filter_select_bit; - - /* Reactivate the filter */ - CAN_FA1R(CAN1) |= filter_select_bit; - - /* Request initialization "leave" */ - CAN_FMR(CAN1) &= ~CAN_FMR_FINIT; + can_filter_id_mask_32bit_init(CAN1, + 0, /* Filter id */ + 0, /* CAN id */ + 0, /* CAN id mask */ + 0, /* FIFO assignement (in this case FIFO0) */ + true); /* Enable the filter */ /* --- Enable CAN rx interrupt -------------------------------------- */ - CAN_IER(CAN1) |= CAN_IER_FMPIE0; -} - -void can_transmit(u32 id, u8 length, u8 data) -{ - u32 mailbox = 0; - - if ((CAN_TSR(CAN1) & CAN_TSR_TME0) == CAN_TSR_TME0) { - mailbox = CAN_MBOX0; - gpio_set(GPIOB, GPIO0); - } else if ((CAN_TSR(CAN1) & CAN_TSR_TME1) == CAN_TSR_TME1) { - mailbox = CAN_MBOX1; - gpio_set(GPIOB, GPIO0); - } else if ((CAN_TSR(CAN1) & CAN_TSR_TME2) == CAN_TSR_TME2) { - mailbox = CAN_MBOX2; - gpio_set(GPIOB, GPIO0); - } else { - mailbox = 0; /* no mailbox */ - gpio_clear(GPIOB, GPIO0); - } - - if ( mailbox != 0 ) { /* check if we have an empty mailbox */ - /* Set the ID */ - CAN_TIxR(CAN1, mailbox) |= id << CAN_TIxR_STID_SHIFT; - - /* Set the DLC */ - CAN_TDTxR(CAN1, mailbox) &= 0xFFFFFFFF0; - CAN_TDTxR(CAN1, mailbox) |= length & CAN_TDTxR_DLC_MASK; - - /* Set the data */ - CAN_TDLxR(CAN1, mailbox) = data; - CAN_TDHxR(CAN1, mailbox) = 0x00000000; - - /* Request transmission */ - CAN_TIxR(CAN1, mailbox) |= CAN_TIxR_TXRQ; - } + can_enable_irq(CAN1, CAN_IER_FMPIE0); } void sys_tick_handler() { static int temp32 = 0; + static u8 data[8] = {0,1,2,0,0,0,0,0}; temp32++; /* we call this handler every 1ms so 1000ms = 1s on/off */ if (temp32 == 1000) { - gpio_toggle(GPIOA, GPIO6); /* LED2 on/off */ temp32 = 0; /* --- Transmit CAN frame ----------------------------------- */ - can_transmit(0, 0, 10); + data[0]++; + if(can_transmit(CAN1, + 0, /* (EX/ST)ID: CAN id */ + false, /* IDE: CAN id extended? */ + false, /* RTR: Request Transmit? */ + 8, /* DLC: Data Length */ + data) == -1) { + gpio_set(GPIOA, GPIO6); /* LED0 off */ + gpio_set(GPIOA, GPIO7); /* LED1 off */ + gpio_clear(GPIOB, GPIO0); /* LED2 on */ + gpio_set(GPIOB, GPIO1); /* LED3 off */ + } } } void usb_lp_can_rx0_isr(void) { - gpio_toggle(GPIOA, GPIO7); - CAN_RF0R(CAN1) |= CAN_RF0R_RFOM0; + u32 id; + bool ext; + bool rtr; + u32 fmi; + u8 length; + u8 data[8]; + + can_receive(CAN1, 0, false, &id, &ext, &rtr, &fmi, &length, data); + + if (data[0] & 1) { + gpio_clear(GPIOA, GPIO6); + } else { + gpio_set(GPIOA, GPIO6); + } + + if (data[0] & 2) { + gpio_clear(GPIOA, GPIO7); + } else { + gpio_set(GPIOA, GPIO7); + } + + if (data[0] & 4) { + gpio_clear(GPIOB, GPIO0); + } else { + gpio_set(GPIOB, GPIO0); + } + + if (data[0] & 8) { + gpio_clear(GPIOB, GPIO1); + } else { + gpio_set(GPIOB, GPIO1); + } + + can_fifo_release(CAN1, 0); } int main(void) diff --git a/include/libopenstm32/can.h b/include/libopenstm32/can.h index dfa4f5cf..43de3740 100644 --- a/include/libopenstm32/can.h +++ b/include/libopenstm32/can.h @@ -528,10 +528,9 @@ #define CAN_RDTxR_TIME_MASK (0xFFFF << 15) #define CAN_RDTxR_TIME_SHIFT 15 -/* 15:6 Reserved, forced by hardware to 0 */ - -/* TGT: Transmit global time */ -#define CAN_RDTxR_TGT (1 << 5) +/* FMI[7:0]: Filter match index */ +#define CAN_RDTxR_FMI_MASK (0xFF << 8) +#define CAN_RDTxR_FMI_SHIFT 8 /* 7:4 Reserved, forced by hardware to 0 */ @@ -607,4 +606,42 @@ /* FB[31:0]: Filter bits */ +/* --- CAN functions -------------------------------------------------------- */ + +void can_reset(u32 canport); +int can_init(u32 canport, + bool ttcm, bool abom, bool awum, bool nart, bool rflm, bool txfp, + u32 sjw, u32 ts1, u32 ts2, u32 brp); + +void can_filter_init(u32 canport, u32 nr, bool scale_32bit, bool id_list_mode, + u32 fr1, u32 fr2, + u32 fifo, bool enable); + +void can_filter_id_mask_16bit_init(u32 canport, u32 nr, + u16 id1, u16 mask1, + u16 id2, u16 mask2, + u32 fifo, bool enable); +void can_filter_id_mask_32bit_init(u32 canport, u32 nr, + u32 id, u32 mask, + u32 fifo, bool enable); +void can_filter_id_list_16bit_init(u32 canport, u32 nr, + u16 id1, u16 id2, + u16 id3, u16 id4, + u32 fifo, bool enable); +void can_filter_id_list_32bit_init(u32 canport, u32 nr, + u32 id1, u32 id2, + u32 fifo, bool enable); + +void can_enable_irq(u32 canport, u32 irq); +void can_disable_irq(u32 canport, u32 irq); + +int can_transmit(u32 canport, u32 id, + bool ext, bool rtr, + u8 length, u8 *data); +void can_receive(u32 canport, u8 fifo, bool release, + u32 *id, bool *ext, bool *rtr, u32 *fmi, + u8 *length, u8 *data); + +void can_fifo_release(u32 canport, u8 fifo); + #endif /* LIBOPENSTM32_CAN_H */ diff --git a/include/libopenstm32/common.h b/include/libopenstm32/common.h index fc06dd9b..81b2f52a 100644 --- a/include/libopenstm32/common.h +++ b/include/libopenstm32/common.h @@ -21,6 +21,7 @@ #define LIBOPENSTM32_COMMON_H #include +#include /* Type definitions for shorter and nicer code */ typedef int8_t s8; diff --git a/lib/Makefile b/lib/Makefile index 2e57624e..5f619937 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -29,7 +29,7 @@ CFLAGS = -Os -g -Wall -Wextra -I../include -fno-common \ ARFLAGS = rcs OBJS = vector.o rcc.o gpio.o usart.o adc.o spi.o flash.o nvic.o \ rtc.o i2c.o dma.o systick.o exti.o scb.o ethernet.o \ - usb_f103.o usb.o usb_control.o usb_standard.o + usb_f103.o usb.o usb_control.o usb_standard.o can.o VPATH += usb diff --git a/lib/can.c b/lib/can.c new file mode 100644 index 00000000..eb7ac58b --- /dev/null +++ b/lib/can.c @@ -0,0 +1,352 @@ +/* + * This file is part of the libopenstm32 project. + * + * Copyright (C) 2010 Piotr Esden-Tempski + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include + +void can_reset(u32 canport) +{ + if(canport == CAN1){ + rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN1RST); + rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN1RST); + }else{ + rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN2RST); + rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN2RST); + } +} + +int can_init(u32 canport, + bool ttcm, bool abom, bool awum, bool nart, bool rflm, bool txfp, + u32 sjw, u32 ts1, u32 ts2, u32 brp) +{ + u32 wait_ack = 0x00000000; + u32 can_msr_inak_timeout = 0x0000FFFF; + int ret = 0; + + /* Exit from sleep mode */ + CAN_MCR(canport) &= ~CAN_MCR_SLEEP; + + /* Request initialization "enter" */ + CAN_MCR(canport) |= CAN_MCR_INRQ; + + /* Wait for acknowledge */ + while ((wait_ack != can_msr_inak_timeout) && + ((CAN_MSR(canport) & CAN_MSR_INAK) != CAN_MSR_INAK)) { + wait_ack++; + } + + /* Check the acknowledge */ + if ((CAN_MSR(canport) & CAN_MSR_INAK) != CAN_MSR_INAK) { + ret = 1; + } else { + + /* set the automatic bus-off management */ + if (ttcm) { + CAN_MCR(canport) |= CAN_MCR_TTCM; + } else { + CAN_MCR(canport) &= ~CAN_MCR_TTCM; + } + + if (abom) { + CAN_MCR(canport) |= CAN_MCR_ABOM; + } else { + CAN_MCR(canport) &= ~CAN_MCR_ABOM; + } + + + if (awum) { + CAN_MCR(canport) |= CAN_MCR_AWUM; + } else { + CAN_MCR(canport) &= ~CAN_MCR_AWUM; + } + + if (nart) { + CAN_MCR(canport) |= CAN_MCR_NART; + } else { + CAN_MCR(canport) &= ~CAN_MCR_NART; + } + + + if (rflm) { + CAN_MCR(canport) |= CAN_MCR_RFLM; + } else { + CAN_MCR(canport) &= ~CAN_MCR_RFLM; + } + + if (txfp) { + CAN_MCR(canport) |= CAN_MCR_TXFP; + } else { + CAN_MCR(canport) &= ~CAN_MCR_TXFP; + } + + /* Set bit timings */ + CAN_BTR(canport) = sjw | + ts2 | + ts1 | + (u32)(CAN_BTR_BRP_MASK & (brp - 1)); + + /* Request initialization "leave" */ + CAN_MCR(canport) &= ~CAN_MCR_INRQ; + + /* Wait for acknowledge */ + wait_ack = 0x00000000; + while ((wait_ack != can_msr_inak_timeout) && + ((CAN_MSR(canport) & CAN_MSR_INAK) == CAN_MSR_INAK)) { + wait_ack++; + } + + if ((CAN_MSR(canport) & CAN_MSR_INAK) == CAN_MSR_INAK) { + ret = 1; + } + } + + + return ret; +} + +void can_filter_init(u32 canport, u32 nr, bool scale_32bit, bool id_list_mode, + u32 fr1, u32 fr2, + u32 fifo, bool enable) +{ + u32 filter_select_bit = 0x00000001 << nr; + + /* Request initialization "enter" */ + CAN_FMR(canport) |= CAN_FMR_FINIT; + + /* Deactivate the filter */ + CAN_FA1R(canport) &= ~filter_select_bit; + + if (scale_32bit) { + /* Set 32-bit scale for the filter */ + CAN_FS1R(canport) |= filter_select_bit; + } else { + /* Set 16-bit scale for the filter */ + CAN_FS1R(canport) &= ~filter_select_bit; + } + + if (id_list_mode) { + /* Set filter mode to id list mode */ + CAN_FM1R(canport) |= filter_select_bit; + } else { + /* Set filter mode to id/mask mode */ + CAN_FM1R(canport) &= ~filter_select_bit; + } + + /* Set the first filter register */ + CAN_FiR1(canport, nr) = fr1; + + /* Set the second filter register */ + CAN_FiR2(canport, nr) = fr2; + + if (fifo) { + /* Select FIFO1 as filter assignement */ + CAN_FFA1R(canport) |= filter_select_bit; + } else { + /* Select FIFO0 as filter assignement */ + CAN_FFA1R(canport) &= ~filter_select_bit; + } + + if (enable) { + /* Activate the filter */ + CAN_FA1R(canport) |= filter_select_bit; + } + + /* Request initialization "leave" */ + CAN_FMR(canport) &= ~CAN_FMR_FINIT; + +} + +void can_filter_id_mask_16bit_init(u32 canport, u32 nr, + u16 id1, u16 mask1, + u16 id2, u16 mask2, + u32 fifo, bool enable) +{ + can_filter_init(canport, nr, false, false, + ((u32)id1 << 16) | (u32)mask1, + ((u32)id2 << 16) | (u32)mask2, + fifo, enable); +} + + +void can_filter_id_mask_32bit_init(u32 canport, u32 nr, + u32 id, u32 mask, + u32 fifo, bool enable) +{ + can_filter_init(canport, nr, true, false, + id, mask, + fifo, enable); +} + +void can_filter_id_list_16bit_init(u32 canport, u32 nr, + u16 id1, u16 id2, + u16 id3, u16 id4, + u32 fifo, bool enable) +{ + can_filter_init(canport, nr, false, true, + ((u32)id1 << 16) | (u32)id2, + ((u32)id3 << 16) | (u32)id4, + fifo, enable); +} + +void can_filter_id_list_32bit_init(u32 canport, u32 nr, + u32 id1, u32 id2, + u32 fifo, bool enable) +{ + can_filter_init(canport, nr, true, true, + id1, id2, + fifo, enable); +} + +void can_enable_irq(u32 canport, u32 irq) +{ + + CAN_IER(canport) |= irq; +} + +void can_disable_irq(u32 canport, u32 irq) +{ + + CAN_IER(canport) &= ~irq; +} + +int can_transmit(u32 canport, u32 id, bool ext, bool rtr, u8 length, u8 *data) +{ + int ret = 0; + u32 mailbox = 0; + int i; + + if ((CAN_TSR(canport) & CAN_TSR_TME0) == CAN_TSR_TME0) { + ret = 0; + mailbox = CAN_MBOX0; + } else if ((CAN_TSR(canport) & CAN_TSR_TME1) == CAN_TSR_TME1) { + ret = 1; + mailbox = CAN_MBOX1; + } else if ((CAN_TSR(canport) & CAN_TSR_TME2) == CAN_TSR_TME2) { + ret = 2; + mailbox = CAN_MBOX2; + } else { + ret = -1; + } + + if (ret != -1) { /* check if we have an empty mailbox */ + if (ext) { + /* Set extended id */ + CAN_TIxR(canport, mailbox) |= id << CAN_TIxR_EXID_SHIFT; + /* Set extended id indicator bit */ + CAN_TIxR(canport, mailbox) |= CAN_TIxR_IDE; + } else { + /* Set standard id */ + CAN_TIxR(canport, mailbox) |= id << CAN_TIxR_STID_SHIFT; + /* Unset extended id indicator bit */ + CAN_TIxR(canport, mailbox) &= ~CAN_TIxR_IDE; + } + + if (rtr) { + /* Set remote transmission request bit */ + CAN_TIxR(canport, mailbox) |= CAN_TIxR_RTR; + } else { + /* Unset remote transmission request bit */ + CAN_TIxR(canport, mailbox) &= ~CAN_TIxR_RTR; + } + + /* Set the DLC */ + CAN_TDTxR(canport, mailbox) &= 0xFFFFFFFF0; + CAN_TDTxR(canport, mailbox) |= length & CAN_TDTxR_DLC_MASK; + + /* Set the data */ + CAN_TDLxR(canport, mailbox) = 0; + CAN_TDHxR(canport, mailbox) = 0; + for (i = 0; (i < 4) && (i < length); i++) { + CAN_TDLxR(canport, mailbox) |= (u32)data[i] << (8 * i); + } + for (i = 4; (i < 8) && (i < length); i++) { + CAN_TDHxR(canport, mailbox) |= (u32)data[i] << (8 * (i-4)); + } + + /* Request transmission */ + CAN_TIxR(canport, mailbox) |= CAN_TIxR_TXRQ; + } + + return ret; +} + +void can_fifo_release(u32 canport, u8 fifo) +{ + if (fifo == 0) { + CAN_RF0R(canport) |= CAN_RF1R_RFOM1; + } else { + CAN_RF1R(canport) |= CAN_RF1R_RFOM1; + } +} + +void can_receive(u32 canport, u8 fifo, bool release, + u32 *id, bool *ext, bool *rtr, u32 *fmi, + u8 *length, u8 *data) +{ + u32 fifo_id = 0; + int i; + + if (fifo == 0) { + fifo_id = CAN_FIFO0; + } else { + fifo_id = CAN_FIFO1; + } + + /* get type of CAN id and CAN id */ + if (CAN_RIxR(canport, fifo_id) & CAN_RIxR_IDE) { + *ext = true; + /* Get extended CAN id */ + *id = ((CAN_RIxR(canport, fifo_id) & CAN_RIxR_EXID_MASK) > + CAN_RIxR_EXID_SHIFT); + } else { + *ext = false; + /* Get standard CAN id */ + *id = ((CAN_RIxR(canport, fifo_id) & CAN_RIxR_STID_MASK) > + CAN_RIxR_STID_SHIFT); + } + + /* get request transmit flag */ + if (CAN_RIxR(canport, fifo_id) & CAN_RIxR_RTR) { + *rtr = true; + } else { + *rtr = false; + } + + /* get filter match id */ + *fmi = ((CAN_RDTxR(canport, fifo_id) & CAN_RDTxR_FMI_MASK) > + CAN_RDTxR_FMI_SHIFT); + + /* get data length */ + *length = CAN_RDTxR(canport, fifo_id) & CAN_RDTxR_DLC_MASK; + + /* get data */ + for (i=0; (i < 4) && (i < *length); i++) { + data[i] = (CAN_RDLxR(canport, fifo_id) >> (8 * i)) & 0xFF; + } + + for (i=4; (i < 8) && (i < *length); i++) { + data[i] = (CAN_RDHxR(canport, fifo_id) >> (8 * (i - 4))) & 0xFF; + } + + /* release the fifo */ + if (release) { + can_fifo_release(CAN1, 0); + } +}