diff --git a/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.BitCalc.cs b/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.BitCalc.cs index dd0a03531..b7bf71090 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.BitCalc.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.BitCalc.cs @@ -1,4 +1,5 @@ using Meadow.Hardware; +using System; namespace Meadow.Foundation.ICs.CAN; @@ -41,7 +42,18 @@ public partial class Mcp2515 break; case CanOscillator.Osc_10MHz: - // TODO: add supported things here + switch (bitrate) + { + // case CanBitrate.Can_125kbps: + // return (0x03, 0xb8, 0x05); + case CanBitrate.Can_250kbps: + return (0x01, 0x90, 0x02); + case CanBitrate.Can_500kbps: + return (0x00, 0x90, 0x02); + case CanBitrate.Can_1Mbps: + return (0x00, 0x80, 0x00); + // TODO: add supported things here + } break; case CanOscillator.Osc_16MHz: @@ -110,6 +122,39 @@ public partial class Mcp2515 } - throw new System.NotSupportedException("Provided Bitrate and Oscillator frequency is not supported"); + // if we don't have a fixed, pre-calculated value, try to calculate one + var freq = oscillator switch + { + CanOscillator.Osc_8MHz => 8_000_000, + CanOscillator.Osc_10MHz => 10_000_000, + CanOscillator.Osc_16MHz => 16_000_000, + CanOscillator.Osc_20MHz => 20_000_000, + _ => throw new NotSupportedException(), + }; + + return CalculateConfigForOscillatorAndBitrate((int)oscillator, (int)bitrate); + } + + private (byte CFG1, byte CFG2, byte CFG3) CalculateConfigForOscillatorAndBitrate(int oscillatorFreq, int bitRate) + { + int TQ = 16; // Assume 16 time quanta per bit time + int PropSeg = 3; // Propagation segment + int PhaseSeg1 = 5; // Phase Segment 1 + int PhaseSeg2 = 5; // Phase Segment 2 + int SJW = 1; // Synchronization Jump Width (1 TQ) + + // Calculate Baud Rate Prescaler (BRP) + int brp = (oscillatorFreq / (2 * bitRate * TQ)) - 1; + if (brp < 0 || brp > 63) // BRP must fit in 6 bits + { + throw new ArgumentOutOfRangeException("Cannot calculate BRP for the given oscillator frequency and bitrate."); + } + + // Calculate CNF1, CNF2, CNF3 + var cfg1 = (byte)(((SJW - 1) << 6) | (brp & 0x3F)); // SJW is 2 bits, BRP is 6 bits + var cfg2 = (byte)(0x80 | ((PhaseSeg1 - 1) << 3) | (PropSeg - 1)); // Set SAM = 1 for single sampling + var cfg3 = (byte)(PhaseSeg2 - 1); // PhaseSeg2 + + return (cfg1, cfg2, cfg3); } } diff --git a/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.CanBus.cs b/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.CanBus.cs index de622f105..362ffbf26 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.CanBus.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.CanBus.cs @@ -12,7 +12,8 @@ public class Mcp2515CanBus : ICanBus /// public event EventHandler? FrameReceived; - public event EventHandler? BusError; + /// + public event EventHandler? BusError; private Mcp2515 Controller { get; } @@ -105,8 +106,20 @@ private void OnInterruptPortChanged(object sender, DigitalPortResult e) } break; case InterruptCode.Error: - var errors = Controller.ReadRegister(Register.EFLG)[0]; - BusError?.Invoke(this, errors); + if (BusError != null) + { + var errors = Controller.ReadRegister(Register.EFLG)[0]; + // read the error counts + var tec = Controller.ReadRegister(Register.TEC)[0]; + var rec = Controller.ReadRegister(Register.REC)[0]; + BusError.Invoke(this, new CanErrorInfo + { + ReceiveErrorCount = rec, + TransmitErrorCount = tec + }); + // clear the error interrupt + Controller.ClearInterrupt(InterruptFlag.ERRIF | InterruptFlag.MERRF); + } break; } } diff --git a/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.Enums.cs b/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.Enums.cs index 8e72ee632..9bd82b53f 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.Enums.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.Enums.cs @@ -6,10 +6,10 @@ public partial class Mcp2515 { public enum CanOscillator { - Osc_8MHz, - Osc_10MHz, - Osc_16MHz, - Osc_20MHz, + Osc_8MHz = 8_000_000, + Osc_10MHz = 10_000_000, + Osc_16MHz = 16_000_000, + Osc_20MHz = 20_000_000, } private enum Register : byte @@ -143,8 +143,8 @@ private enum Control : byte private enum Status : byte { NONE = 0, - RX0IF = (1 << 0), - RX1IF = (1 << 1) + RX0IF = 1 << 0, + RX1IF = 1 << 1 } private enum Result : byte diff --git a/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.cs b/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.cs index b451aafe0..53c456387 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.CAN.Mcp2515/Driver/Mcp2515.cs @@ -83,9 +83,7 @@ private void Initialize(CanBitrate bitrate, CanOscillator oscillator) if (InterruptPort != null) { - // TODO: add error condition handling - ConfigureInterrupts(InterruptEnable.RXB0 | InterruptEnable.RXB1 | InterruptEnable.ERR | InterruptEnable.MSG_ERR); - //ConfigureInterrupts(InterruptEnable.RXB0 | InterruptEnable.RXB1); + ConfigureInterrupts(InterruptEnable.RXB0 | InterruptEnable.RXB1 | InterruptEnable.ERR); ClearInterrupt((InterruptFlag)0xff); } else @@ -192,7 +190,7 @@ private void WriteFrame(ICanFrame frame, int bufferNumber) { // put the frame id into a buffer (0-2) var sidh = (byte)(sdf.ID >> 3); - var sidl = (byte)(sdf.ID << 5 & 0xe0); + var sidl = (byte)((sdf.ID << 5) & 0xe0); WriteRegister(ctrl_reg + 1, sidh); WriteRegister(ctrl_reg + 2, sidl); } @@ -200,7 +198,7 @@ private void WriteFrame(ICanFrame frame, int bufferNumber) { // put the frame id into a buffer (0-2) var sidh = (byte)(srf.ID >> 3); - var sidl = (byte)(srf.ID << 5 & 0xe0); + var sidl = (byte)((srf.ID << 5) & 0xe0); WriteRegister(ctrl_reg + 1, sidh); WriteRegister(ctrl_reg + 2, sidl); diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.PCanBasic/Driver/PCanBus.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.PCanBasic/Driver/PCanBus.cs index de5f6c489..32c909301 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.PCanBasic/Driver/PCanBus.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.PCanBasic/Driver/PCanBus.cs @@ -10,6 +10,8 @@ public class PCanBus : ICanBus { /// public event EventHandler? FrameReceived; + /// + public event EventHandler? BusError; /// public CanAcceptanceFilterCollection AcceptanceFilters { get; } = new(5); diff --git a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.PCanBasic/Driver/PCanFdBus.cs b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.PCanBasic/Driver/PCanFdBus.cs index 281a0c3f4..307f1d15a 100644 --- a/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.PCanBasic/Driver/PCanFdBus.cs +++ b/Source/Meadow.Foundation.Peripherals/ICs.IOExpanders.PCanBasic/Driver/PCanFdBus.cs @@ -4,6 +4,11 @@ namespace ICs.IOExpanders.PCanBasic; public class PCanFdBus : ICanBus { + /// + public event EventHandler? FrameReceived; + /// + public event EventHandler? BusError; + internal PCanFdBus(PCanConfiguration configuration) { throw new NotImplementedException(); @@ -13,8 +18,6 @@ internal PCanFdBus(PCanConfiguration configuration) public CanAcceptanceFilterCollection AcceptanceFilters => throw new NotImplementedException(); - public event EventHandler? FrameReceived; - public void ClearReceiveBuffers() { throw new NotImplementedException();