From 8e084b1517088036e3db9bbd255b1c231cd2a108 Mon Sep 17 00:00:00 2001 From: Uwe Hermann Date: Thu, 30 Dec 2010 02:12:31 +0100 Subject: Move STM32-specific source to lib/stm32 subdir. --- lib/stm32/can.c | 305 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 lib/stm32/can.c (limited to 'lib/stm32/can.c') diff --git a/lib/stm32/can.c b/lib/stm32/can.c new file mode 100644 index 0000000..baddab3 --- /dev/null +++ b/lib/stm32/can.c @@ -0,0 +1,305 @@ +/* + * 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) + return 1; + + /* 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; + + /* Select FIFO0 or FIFO1 as filter assignement. */ + if (fifo) + CAN_FFA1R(canport) |= filter_select_bit; /* FIFO1 */ + else + CAN_FFA1R(canport) &= ~filter_select_bit; /* FIFO0 */ + + if (enable) + CAN_FA1R(canport) |= filter_select_bit; /* Activate filter. */ + + /* 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, i; + u32 mailbox = 0; + + 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; + } + + /* Check if we have an empty mailbox. */ + if (ret == -1) + return ret; + + 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; + } + + /* Set/clear remote transmission request bit. */ + if (rtr) + CAN_TIxR(canport, mailbox) |= CAN_TIxR_RTR; /* Set */ + else + CAN_TIxR(canport, mailbox) &= ~CAN_TIxR_RTR; /* Clear */ + + /* 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); +} -- cgit v1.2.3