From ef05ba2ea170844c7bd92baba75c8301401af3ba Mon Sep 17 00:00:00 2001 From: Patricio Whittingslow Date: Sat, 21 Feb 2026 09:20:47 -0300 Subject: [PATCH] delete old can --- src/machine/_old_stm32g0_can.go | 711 -------------------------------- 1 file changed, 711 deletions(-) delete mode 100644 src/machine/_old_stm32g0_can.go diff --git a/src/machine/_old_stm32g0_can.go b/src/machine/_old_stm32g0_can.go deleted file mode 100644 index 01bf523df..000000000 --- a/src/machine/_old_stm32g0_can.go +++ /dev/null @@ -1,711 +0,0 @@ -//go:build stm32g0b1 - -package machine - -import ( - "device/stm32" - "errors" - "runtime/interrupt" - "unsafe" -) - -// FDCAN Message RAM configuration -// STM32G0B1 SRAMCAN base address: 0x4000B400 -// Each FDCAN instance has its own message RAM area -const ( - sramcanBase = 0x4000B400 - - // Message RAM layout sizes (matching STM32 HAL) - sramcanFLSNbr = 28 // Max. Filter List Standard Number - sramcanFLENbr = 8 // Max. Filter List Extended Number - sramcanRF0Nbr = 3 // RX FIFO 0 Elements Number - sramcanRF1Nbr = 3 // RX FIFO 1 Elements Number - sramcanTEFNbr = 3 // TX Event FIFO Elements Number - sramcanTFQNbr = 3 // TX FIFO/Queue Elements Number - - // Element sizes in bytes - sramcanFLSSize = 1 * 4 // Filter Standard Element Size - sramcanFLESize = 2 * 4 // Filter Extended Element Size - sramcanRF0Size = 18 * 4 // RX FIFO 0 Element Size (for 64-byte data) - sramcanRF1Size = 18 * 4 // RX FIFO 1 Element Size - sramcanTEFSize = 2 * 4 // TX Event FIFO Element Size - sramcanTFQSize = 18 * 4 // TX FIFO/Queue Element Size - - // Start addresses (offsets from base) - sramcanFLSSA = 0 - sramcanFLESA = sramcanFLSSA + (sramcanFLSNbr * sramcanFLSSize) - sramcanRF0SA = sramcanFLESA + (sramcanFLENbr * sramcanFLESize) - sramcanRF1SA = sramcanRF0SA + (sramcanRF0Nbr * sramcanRF0Size) - sramcanTEFSA = sramcanRF1SA + (sramcanRF1Nbr * sramcanRF1Size) - sramcanTFQSA = sramcanTEFSA + (sramcanTEFNbr * sramcanTEFSize) - sramcanSize = sramcanTFQSA + (sramcanTFQNbr * sramcanTFQSize) -) - -// FDCAN element masks (for parsing message RAM) -const ( - fdcanElementMaskSTDID = 0x1FFC0000 // Standard Identifier - fdcanElementMaskEXTID = 0x1FFFFFFF // Extended Identifier - fdcanElementMaskRTR = 0x20000000 // Remote Transmission Request - fdcanElementMaskXTD = 0x40000000 // Extended Identifier flag - fdcanElementMaskESI = 0x80000000 // Error State Indicator - fdcanElementMaskTS = 0x0000FFFF // Timestamp - fdcanElementMaskDLC = 0x000F0000 // Data Length Code - fdcanElementMaskBRS = 0x00100000 // Bit Rate Switch - fdcanElementMaskFDF = 0x00200000 // FD Format - fdcanElementMaskEFC = 0x00800000 // Event FIFO Control - fdcanElementMaskMM = 0xFF000000 // Message Marker - fdcanElementMaskFIDX = 0x7F000000 // Filter Index - fdcanElementMaskANMF = 0x80000000 // Accepted Non-matching Frame -) - -// Interrupt flags -const ( - FDCAN_IT_RX_FIFO0_NEW_MESSAGE = 0x00000001 - FDCAN_IT_RX_FIFO0_FULL = 0x00000002 - FDCAN_IT_RX_FIFO0_MSG_LOST = 0x00000004 - FDCAN_IT_RX_FIFO1_NEW_MESSAGE = 0x00000010 - FDCAN_IT_RX_FIFO1_FULL = 0x00000020 - FDCAN_IT_RX_FIFO1_MSG_LOST = 0x00000040 - FDCAN_IT_TX_COMPLETE = 0x00000200 - FDCAN_IT_TX_ABORT_COMPLETE = 0x00000400 - FDCAN_IT_TX_FIFO_EMPTY = 0x00000800 - FDCAN_IT_BUS_OFF = 0x02000000 - FDCAN_IT_ERROR_WARNING = 0x01000000 - FDCAN_IT_ERROR_PASSIVE = 0x00800000 -) - -// FDCAN represents an FDCAN peripheral -type FDCAN struct { - Bus *stm32.FDCAN_Type - TxAltFuncSelect uint8 - RxAltFuncSelect uint8 - Interrupt interrupt.Interrupt - instance uint8 -} - -// FDCANTransferRate represents CAN bus transfer rates -type FDCANTransferRate uint32 - -const ( - FDCANTransferRate125kbps FDCANTransferRate = 125000 - FDCANTransferRate250kbps FDCANTransferRate = 250000 - FDCANTransferRate500kbps FDCANTransferRate = 500000 - FDCANTransferRate1000kbps FDCANTransferRate = 1000000 - FDCANTransferRate2000kbps FDCANTransferRate = 2000000 // FD only - FDCANTransferRate4000kbps FDCANTransferRate = 4000000 // FD only -) - -// FDCANMode represents the FDCAN operating mode -type FDCANMode uint8 - -const ( - FDCANModeNormal FDCANMode = 0 - FDCANModeBusMonitoring FDCANMode = 1 - FDCANModeInternalLoopback FDCANMode = 2 - FDCANModeExternalLoopback FDCANMode = 3 -) - -// FDCANConfig holds FDCAN configuration parameters -type FDCANConfig struct { - TransferRate FDCANTransferRate // Nominal bit rate (arbitration phase) - TransferRateFD FDCANTransferRate // Data bit rate (data phase), must be >= TransferRate - Mode FDCANMode - Tx Pin - Rx Pin - Standby Pin // Optional standby pin for CAN transceiver (set to NoPin if not used) -} - -// FDCANTxBufferElement represents a transmit buffer element -type FDCANTxBufferElement struct { - ESI bool // Error State Indicator - XTD bool // Extended ID flag - RTR bool // Remote Transmission Request - ID uint32 // CAN identifier (11-bit or 29-bit) - MM uint8 // Message Marker - EFC bool // Event FIFO Control - FDF bool // FD Frame indicator - BRS bool // Bit Rate Switch - DLC uint8 // Data Length Code (0-15) - DB [64]byte // Data buffer -} - -// FDCANRxBufferElement represents a receive buffer element -type FDCANRxBufferElement struct { - ESI bool // Error State Indicator - XTD bool // Extended ID flag - RTR bool // Remote Transmission Request - ID uint32 // CAN identifier - ANMF bool // Accepted Non-matching Frame - FIDX uint8 // Filter Index - FDF bool // FD Frame - BRS bool // Bit Rate Switch - DLC uint8 // Data Length Code - RXTS uint16 // RX Timestamp - DB [64]byte // Data buffer -} - -// FDCANFilterConfig represents a filter configuration -type FDCANFilterConfig struct { - Index uint8 // Filter index (0-27 for standard, 0-7 for extended) - Type uint8 // 0=Range, 1=Dual, 2=Classic (ID/Mask) - Config uint8 // 0=Disable, 1=FIFO0, 2=FIFO1, 3=Reject - ID1 uint32 // First ID or filter - ID2 uint32 // Second ID or mask - IsExtendedID bool // true for 29-bit ID, false for 11-bit -} - -var ( - errFDCANInvalidTransferRate = errors.New("FDCAN: invalid TransferRate") - errFDCANInvalidTransferRateFD = errors.New("FDCAN: invalid TransferRateFD") - errFDCANTimeout = errors.New("FDCAN: timeout") - errFDCANTxFifoFull = errors.New("FDCAN: Tx FIFO full") - errFDCANRxFifoEmpty = errors.New("FDCAN: Rx FIFO empty") - errFDCANNotStarted = errors.New("FDCAN: not started") -) - -// DLC to bytes lookup table -var dlcToBytes = [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64} - -// Configure initializes the FDCAN peripheral -func (can *FDCAN) Configure(config FDCANConfig) error { - // Configure standby pin if specified (for CAN transceivers with standby control) - // Setting it low enables the transceiver - if config.Standby != NoPin { - config.Standby.Configure(PinConfig{Mode: PinOutput}) - config.Standby.Low() - } - - // Enable FDCAN clock - enableFDCANClock() - - // Configure TX and RX pins - config.Tx.ConfigureAltFunc(PinConfig{Mode: PinOutput}, can.TxAltFuncSelect) - config.Rx.ConfigureAltFunc(PinConfig{Mode: PinInputFloating}, can.RxAltFuncSelect) - - // Exit from sleep mode - can.Bus.SetCCCR_CSR(0) - - // Wait for sleep mode exit - timeout := 10000 - for can.Bus.GetCCCR_CSA() != 0 { - timeout-- - if timeout == 0 { - return errFDCANTimeout - } - } - - // Request initialization - can.Bus.SetCCCR_INIT(1) - - // Wait for init mode - timeout = 10000 - for can.Bus.GetCCCR_INIT() == 0 { - timeout-- - if timeout == 0 { - return errFDCANTimeout - } - } - - // Enable configuration change - can.Bus.SetCCCR_CCE(1) - - // Configure clock divider (only for FDCAN1) - if can.Bus == stm32.FDCAN1 { - can.Bus.SetCKDIV_PDIV(0) - //can.Bus.CKDIV.Set(0) // No division - } - - // Enable automatic retransmission - can.Bus.SetCCCR_DAR(0) - - // Disable transmit pause - can.Bus.SetCCCR_TXP(0) - - // Enable protocol exception handling - can.Bus.SetCCCR_PXHD(0) - - // Enable FD mode with bit rate switching - can.Bus.SetCCCR_FDOE(1) - can.Bus.SetCCCR_BRSE(1) - - // Configure operating mode - can.Bus.SetCCCR_TEST(0) - can.Bus.SetCCCR_MON(0) - can.Bus.SetCCCR_ASM(0) - can.Bus.SetTEST_LBCK(0) - - switch config.Mode { - case FDCANModeBusMonitoring: - can.Bus.SetCCCR_MON(1) - case FDCANModeInternalLoopback: - can.Bus.SetCCCR_TEST(1) - can.Bus.SetCCCR_MON(1) - can.Bus.SetTEST_LBCK(1) - case FDCANModeExternalLoopback: - can.Bus.SetCCCR_TEST(1) - can.Bus.SetTEST_LBCK(1) - } - - // Set nominal bit timing - // STM32G0 runs at 64MHz, FDCAN clock = PCLK = 64MHz - // Bit time = (1 + NTSEG1 + NTSEG2) * tq - // tq = (NBRP + 1) / fCAN_CLK - if config.TransferRate == 0 { - config.TransferRate = FDCANTransferRate500kbps - } - - nbrp, ntseg1, ntseg2, nsjw, err := can.calculateNominalBitTiming(config.TransferRate) - if err != nil { - return err - } - can.Bus.NBTP.Set(((nsjw - 1) << 25) | ((nbrp - 1) << 16) | ((ntseg1 - 1) << 8) | (ntseg2 - 1)) - - // Set data bit timing (for FD mode) - if config.TransferRateFD == 0 { - config.TransferRateFD = FDCANTransferRate1000kbps - } - if config.TransferRateFD < config.TransferRate { - return errFDCANInvalidTransferRateFD - } - - dbrp, dtseg1, dtseg2, dsjw, err := can.calculateDataBitTiming(config.TransferRateFD) - if err != nil { - return err - } - can.Bus.DBTP.Set(((dbrp - 1) << 16) | ((dtseg1 - 1) << 8) | ((dtseg2 - 1) << 4) | (dsjw - 1)) - - // Configure message RAM - can.configureMessageRAM() - - return nil -} - -// Start enables the FDCAN peripheral for communication -func (can *FDCAN) Start() error { - // Disable configuration change - can.Bus.SetCCCR_CCE(0) - - // Exit initialization mode - can.Bus.SetCCCR_INIT(0) - - // Wait for normal operation - timeout := 10000 - - for can.Bus.GetCCCR_INIT() != 0 { - timeout-- - if timeout == 0 { - return errFDCANTimeout - } - } - - return nil -} - -// Stop disables the FDCAN peripheral -func (can *FDCAN) Stop() error { - // Request initialization - can.Bus.SetCCCR_INIT(1) - - // Wait for init mode - timeout := 10000 - for can.Bus.GetCCCR_INIT() == 0 { - timeout-- - if timeout == 0 { - return errFDCANTimeout - } - } - - // Enable configuration change - can.Bus.SetCCCR_CCE(1) - - return nil -} - -// TxFifoIsFull returns true if the TX FIFO is full -func (can *FDCAN) TxFifoIsFull() bool { - return (can.Bus.TXFQS.Get() & 0x00200000) != 0 // TFQF bit -} - -// TxFifoFreeLevel returns the number of free TX FIFO elements -func (can *FDCAN) TxFifoFreeLevel() int { - return int(can.Bus.TXFQS.Get() & 0x07) // TFFL[2:0] -} - -// RxFifoSize returns the number of messages in RX FIFO 0 -func (can *FDCAN) RxFifoSize() int { - return int(can.Bus.RXF0S.Get() & 0x0F) // F0FL[3:0] -} - -// RxFifoIsEmpty returns true if RX FIFO 0 is empty -func (can *FDCAN) RxFifoIsEmpty() bool { - return (can.Bus.RXF0S.Get() & 0x0F) == 0 -} - -// TxRaw transmits a CAN frame using the raw buffer element structure -func (can *FDCAN) TxRaw(e *FDCANTxBufferElement) error { - // Check if TX FIFO is full - if can.TxFifoIsFull() { - return errFDCANTxFifoFull - } - - // Get put index - putIndex := (can.Bus.TXFQS.Get() >> 16) & 0x03 // TFQPI[1:0] - - // Calculate TX buffer address - sramBase := can.getSRAMBase() - txAddress := sramBase + sramcanTFQSA + (uintptr(putIndex) * sramcanTFQSize) - - // Build first word - var w1 uint32 - id := e.ID - if !e.XTD { - // Standard ID - shift to bits [28:18] - id = (id & 0x7FF) << 18 - } - w1 = id & 0x1FFFFFFF - if e.ESI { - w1 |= fdcanElementMaskESI - } - if e.XTD { - w1 |= fdcanElementMaskXTD - } - if e.RTR { - w1 |= fdcanElementMaskRTR - } - - // Build second word - var w2 uint32 - w2 = uint32(e.DLC) << 16 - if e.FDF { - w2 |= fdcanElementMaskFDF - } - if e.BRS { - w2 |= fdcanElementMaskBRS - } - if e.EFC { - w2 |= fdcanElementMaskEFC - } - w2 |= uint32(e.MM) << 24 - - // Write to message RAM - *(*uint32)(unsafe.Pointer(txAddress)) = w1 - *(*uint32)(unsafe.Pointer(txAddress + 4)) = w2 - - // Copy data bytes - must use 32-bit word access on Cortex-M0+ - dataLen := dlcToBytes[e.DLC&0x0F] - numWords := (dataLen + 3) / 4 - for w := byte(0); w < numWords; w++ { - var word uint32 - baseIdx := w * 4 - for b := byte(0); b < 4 && baseIdx+b < dataLen; b++ { - word |= uint32(e.DB[baseIdx+b]) << (b * 8) - } - *(*uint32)(unsafe.Pointer(txAddress + 8 + uintptr(w)*4)) = word - } - - // Request transmission - can.Bus.TXBAR.Set(1 << putIndex) - - return nil -} - -// Tx transmits a CAN frame with the specified ID and data -func (can *FDCAN) Tx(id uint32, data []byte, isFD, isExtendedID bool) error { - length := byte(len(data)) - if length > 64 { - length = 64 - } - if !isFD && length > 8 { - length = 8 - } - - e := FDCANTxBufferElement{ - ESI: false, - XTD: isExtendedID, - RTR: false, - ID: id, - MM: 0, - EFC: false, - FDF: isFD, - BRS: isFD, - DLC: FDCANLengthToDlc(length, isFD), - } - - for i := byte(0); i < length; i++ { - e.DB[i] = data[i] - } - - return can.TxRaw(&e) -} - -// RxRaw receives a CAN frame into the raw buffer element structure -func (can *FDCAN) RxRaw(e *FDCANRxBufferElement) error { - if can.RxFifoIsEmpty() { - return errFDCANRxFifoEmpty - } - - // Get get index - getIndex := (can.Bus.RXF0S.Get() >> 8) & 0x03 // F0GI[1:0] - - // Calculate RX buffer address - sramBase := can.getSRAMBase() - rxAddress := sramBase + sramcanRF0SA + (uintptr(getIndex) * sramcanRF0Size) - - // Read first word - w1 := *(*uint32)(unsafe.Pointer(rxAddress)) - e.ESI = (w1 & fdcanElementMaskESI) != 0 - e.XTD = (w1 & fdcanElementMaskXTD) != 0 - e.RTR = (w1 & fdcanElementMaskRTR) != 0 - - if e.XTD { - e.ID = w1 & fdcanElementMaskEXTID - } else { - e.ID = (w1 & fdcanElementMaskSTDID) >> 18 - } - - // Read second word - w2 := *(*uint32)(unsafe.Pointer(rxAddress + 4)) - e.RXTS = uint16(w2 & fdcanElementMaskTS) - e.DLC = uint8((w2 & fdcanElementMaskDLC) >> 16) - e.BRS = (w2 & fdcanElementMaskBRS) != 0 - e.FDF = (w2 & fdcanElementMaskFDF) != 0 - e.FIDX = uint8((w2 & fdcanElementMaskFIDX) >> 24) - e.ANMF = (w2 & fdcanElementMaskANMF) != 0 - - // Copy data bytes - must use 32-bit word access on Cortex-M0+ - dataLen := dlcToBytes[e.DLC&0x0F] - numWords := (dataLen + 3) / 4 - for w := byte(0); w < numWords; w++ { - word := *(*uint32)(unsafe.Pointer(rxAddress + 8 + uintptr(w)*4)) - baseIdx := w * 4 - for b := byte(0); b < 4 && baseIdx+b < dataLen; b++ { - e.DB[baseIdx+b] = byte(word >> (b * 8)) - } - } - - // Acknowledge the read - can.Bus.RXF0A.Set(uint32(getIndex)) - - return nil -} - -// Rx receives a CAN frame and returns its components -func (can *FDCAN) Rx() (id uint32, dlc byte, data []byte, isFD, isExtendedID bool, err error) { - e := FDCANRxBufferElement{} - err = can.RxRaw(&e) - if err != nil { - return 0, 0, nil, false, false, err - } - - length := FDCANDlcToLength(e.DLC, e.FDF) - return e.ID, length, e.DB[:length], e.FDF, e.XTD, nil -} - -// SetInterrupt configures interrupt handling for the FDCAN peripheral -func (can *FDCAN) SetInterrupt(ie uint32, callback func(*FDCAN)) error { - if callback == nil { - can.Bus.IE.ClearBits(ie) - return nil - } - - can.Bus.IE.SetBits(ie) - - idx := can.instance - fdcanInstances[idx] = can - - for i := uint(0); i < 32; i++ { - if ie&(1<= sramcanFLENbr { - return errors.New("FDCAN: filter index out of range") - } - - filterAddr := sramBase + sramcanFLESA + (uintptr(config.Index) * sramcanFLESize) - - // Build filter elements - w1 := (uint32(config.Config) << 29) | (config.ID1 & 0x1FFFFFFF) - w2 := (uint32(config.Type) << 30) | (config.ID2 & 0x1FFFFFFF) - - *(*uint32)(unsafe.Pointer(filterAddr)) = w1 - *(*uint32)(unsafe.Pointer(filterAddr + 4)) = w2 - } else { - // Standard filter - if config.Index >= sramcanFLSNbr { - return errors.New("FDCAN: filter index out of range") - } - - filterAddr := sramBase + sramcanFLSSA + (uintptr(config.Index) * sramcanFLSSize) - - // Build filter element - w := (uint32(config.Type) << 30) | - (uint32(config.Config) << 27) | - ((config.ID1 & 0x7FF) << 16) | - (config.ID2 & 0x7FF) - - *(*uint32)(unsafe.Pointer(filterAddr)) = w - } - - return nil -} - -func (can *FDCAN) getSRAMBase() uintptr { - base := uintptr(sramcanBase) - if can.Bus == stm32.FDCAN2 { - base += sramcanSize - } - return base -} - -func (can *FDCAN) configureMessageRAM() { - sramBase := can.getSRAMBase() - - // Clear message RAM - for addr := sramBase; addr < sramBase+sramcanSize; addr += 4 { - *(*uint32)(unsafe.Pointer(addr)) = 0 - } - - // Configure filter counts (using RXGFC register) - // LSS = number of standard filters, LSE = number of extended filters - rxgfc := can.Bus.RXGFC.Get() - rxgfc &= ^uint32(0xFF000000) // Clear LSS and LSE - rxgfc |= (sramcanFLSNbr << 24) // Standard filters - rxgfc |= (sramcanFLENbr << 24) & 0xFF00 // Extended filters (shifted) - can.Bus.RXGFC.Set(rxgfc) -} - -func (can *FDCAN) calculateNominalBitTiming(rate FDCANTransferRate) (brp, tseg1, tseg2, sjw uint32, err error) { - // STM32G0 FDCAN clock = 64MHz - // Target: 80% sample point - // Bit time = (1 + TSEG1 + TSEG2) time quanta - switch rate { - case FDCANTransferRate125kbps: - // 64MHz / 32 = 2MHz, 16 tq per bit = 125kbps - return 32, 13, 2, 4, nil - case FDCANTransferRate250kbps: - // 64MHz / 16 = 4MHz, 16 tq per bit = 250kbps - return 16, 13, 2, 4, nil - case FDCANTransferRate500kbps: - // 64MHz / 8 = 8MHz, 16 tq per bit = 500kbps - return 8, 13, 2, 4, nil - case FDCANTransferRate1000kbps: - // 64MHz / 4 = 16MHz, 16 tq per bit = 1Mbps - return 4, 13, 2, 4, nil - default: - return 0, 0, 0, 0, errFDCANInvalidTransferRate - } -} - -func (can *FDCAN) calculateDataBitTiming(rate FDCANTransferRate) (brp, tseg1, tseg2, sjw uint32, err error) { - // STM32G0 FDCAN clock = 64MHz - // For data phase, we need higher bit rates - switch rate { - case FDCANTransferRate125kbps: - return 32, 13, 2, 4, nil - case FDCANTransferRate250kbps: - return 16, 13, 2, 4, nil - case FDCANTransferRate500kbps: - return 8, 13, 2, 4, nil - case FDCANTransferRate1000kbps: - return 4, 13, 2, 4, nil - case FDCANTransferRate2000kbps: - // 64MHz / 2 = 32MHz, 16 tq per bit = 2Mbps - return 2, 13, 2, 4, nil - case FDCANTransferRate4000kbps: - // 64MHz / 1 = 64MHz, 16 tq per bit = 4Mbps - return 1, 13, 2, 4, nil - default: - return 0, 0, 0, 0, errFDCANInvalidTransferRateFD - } -} - -// FDCANDlcToLength converts a DLC value to actual byte length -func FDCANDlcToLength(dlc byte, isFD bool) byte { - if dlc > 15 { - dlc = 15 - } - length := dlcToBytes[dlc] - if !isFD && length > 8 { - return 8 - } - return length -} - -// FDCANLengthToDlc converts a byte length to DLC value -func FDCANLengthToDlc(length byte, isFD bool) byte { - if !isFD { - if length > 8 { - return 8 - } - return length - } - - switch { - case length <= 8: - return length - case length <= 12: - return 9 - case length <= 16: - return 10 - case length <= 20: - return 11 - case length <= 24: - return 12 - case length <= 32: - return 13 - case length <= 48: - return 14 - default: - return 15 - } -} - -// Interrupt handling -var ( - fdcanInstances [2]*FDCAN - fdcanCallbacks [2][32]func(*FDCAN) -) - -func fdcanHandleInterrupt(idx int) { - if fdcanInstances[idx] == nil { - return - } - - can := fdcanInstances[idx] - ir := can.Bus.IR.Get() - can.Bus.IR.Set(ir) // Clear interrupt flags - - for i := uint(0); i < 32; i++ { - if ir&(1<