-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Must have another device read the bus. #21
Comments
Probably related to #10 Some discussion on Discord working backward from here. I could be reading the datasheets wrong, but I think this may be intended behavior, though perhaps a more friendly exception could be raised. When there is only a sender on the bus, no acknowledgements are received and the bus goes from Active to Passive bus state. The send queue fills up. Various docs and datasheets discuss this (p.9 of an Analog CAN datasheet):
Unfortunately, the Microchip datasheet isn't as clear (to me anyway), but see also Section 4.4 in a TI CAN datasheet. The bus state can be checked before sending to make sure that it is in Active state, signifying that a listener is successfully receiving messages. can_bus = MCP2515(spi, cs)
listener = can_bus.listen()
print(can_bus.state) edit: ah, here we go, in the Microchip MCP2515 datasheet (p.7):
edit 2: Sorry, took me a while to get that the issue occurs with only a sender and a receiver and without a third device. That is unexpected. I have a setup with only a |
so... im an idiot. how can we add that that last part to the mcp2515 module? I can confirm that this code block mcp = CAN(spi, cs, baudrate=1000000)
next_message = None
message_num = 0
while True:
message_count = mcp.unread_message_count
message_num = 0
next_message = mcp.read_message()
while next_message is not None:
message_num += 1
msg = next_message
next_message = mcp.read_message() does not cause mcp.unread_message_count to decrease. I don't believe the received messages are removed from the message buffer.... I can also confirm that this code # SPDX-FileCopyrightText: Copyright (c) 2020 Bryan Siepert for Adafruit Industries
#
# SPDX-License-Identifier: MIT
from time import sleep
import board
import busio
from digitalio import DigitalInOut
from adafruit_mcp2515.canio import Message, RemoteTransmissionRequest
from adafruit_mcp2515 import MCP2515 as CAN
from canmessage import CanMessage
cs = DigitalInOut(board.CAN_CS)
cs.switch_to_output()
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
can_bus = CAN(spi, cs,baudrate=1000000)
cm = CanMessage()
cm.next()
cm.reset()
while True:
with can_bus.listen() as listener:
cm.next()
message = Message(cm.id, data=cm.data)
cm.reset()
send_success = can_bus.send(message)
print("Send success:", send_success)
print(f"Send details: id{message.id} d{message.data}")
message_count = listener.in_waiting()
print(message_count, "messages available")
for _i in range(message_count):
msg = listener.receive()
print("Message from ", hex(msg.id))
if isinstance(msg, Message):
print("message data:", msg.data)
if isinstance(msg, RemoteTransmissionRequest):
print("RTR length:", msg.length)
sleep(1) is unable to read the messages it puts on the bus if that helps. |
I just got two RP2040 Feathers, each with MCP2515 FeatherWings, to talk to each other with nothing else on the bus. A sends, B receives, B sends a CircuitPython-level code acknowledgement, A receives that acknowledgement before sending the next message. Maybe the code is sufficiently different? Not sure. My code is kind of a mess, in the middle of evolving it to add features. I'll try to pare it down (strip the acknowledgements and other fluff) and post code. |
I think this is the issue: mcp = CAN(spi, cs, silent=True,baudrate=1000000) In Silent mode, the receiver can't assert a dominant ACK, so sender thinks the bus has no other devices. I think it needs to be in Loopback mode to read its own messages? FWIW, here's the pared-down code, which works even if the receiver is interrupted by control-C (I think perhaps library should take device out of normal active mode before exiting).: Receiverimport struct
import time
import board
import busio
import digitalio
try:
import canio
NATIVE = True
except ImportError:
NATIVE = False
import adafruit_mcp2515.canio as canio
from adafruit_mcp2515 import MCP2515
#
# CAN LISTENER
#
DEBUG = True
RCVRID = 0x100
MSGTIMEOUT = 5
def can_recv_msg():
while True:
msg = listener.receive()
if (can_bus.transmit_error_count > 0) or (can_bus.receive_error_count > 0):
print(f"🔴 MSG tx_err={can_bus.transmit_error_count} rx_err={can_bus.receive_error_count}")
if msg is None:
if DEBUG: print("🟡 MSG not received within timeout")
continue
if DEBUG: print(f"MSG {msg.data} from={hex(msg.id)}")
if isinstance(msg, canio.Message):
break
else:
if DEBUG: print("🟡 not a canio message")
return msg
time.sleep(3) # wait for serial
print(f"{'='*25}")
if NATIVE:
can_bus = canio.CAN(rx=board.RX, tx=board.TX, baudrate=500_000, auto_restart=True)
else:
cs = digitalio.DigitalInOut(board.D5)
cs.switch_to_output()
spi = board.SPI()
can_bus = MCP2515(spi, cs, baudrate=500_000)
listener = can_bus.listen(timeout=MSGTIMEOUT)
old_bus_state = None
while True:
bus_state = can_bus.state
if bus_state != old_bus_state:
print(f"🟣 BUS state changed to {bus_state}")
old_bus_state = bus_state
print(f"Receiving...")
if DEBUG: print(f"MSG avail={listener.in_waiting()} unread={can_bus.unread_message_count}")
msg = can_recv_msg()
print(f"{'-'*25}") Senderimport random
import math
import struct
import time
import board
import busio
import digitalio
try:
import canio
NATIVE = True
except ImportError:
NATIVE = False
import adafruit_mcp2515.canio as canio
from adafruit_mcp2515 import MCP2515
#
# CAN SENDER
#
DEBUG = False
SENDERID = 0x400
def can_send_msg(data):
message = canio.Message(id=SENDERID, data=data)
can_bus.send(message)
if (can_bus.transmit_error_count > 0) or (can_bus.receive_error_count > 0):
print(f"🔴 MSG tx_err={can_bus.transmit_error_count} rx_err={can_bus.receive_error_count}")
print(f"MSG {data} len={len(data)}")
return
time.sleep(3) # wait for serial
print(f"{'='*25}")
if NATIVE:
can_bus = canio.CAN(rx=board.RX, tx=board.TX, baudrate=500_000, auto_restart=True)
else:
cs = digitalio.DigitalInOut(board.D5)
cs.switch_to_output()
spi = board.SPI()
can_bus = MCP2515(spi, cs, baudrate=500_000)
old_bus_state = None
while True:
bus_state = can_bus.state
if bus_state != old_bus_state:
print(f"🟣 BUS state changed to {bus_state}")
old_bus_state = bus_state
print(f"Sending...")
data = "".join(random.choice("0123456789ABCDEF") for i in range(random.randint(1, 6))).encode()
can_send_msg(data)
print(f"{'-'*25}")
time.sleep(1) |
Output of above code illustrates the failure mode, but it takes either a receiver hard reset (without the code running after), or going into REPL and manually putting the receiver can bus into silent mode:
The MCP2515 has three send buffers. The first message accumulates enough on-chip send retry fails to put the bus into |
This was killing me to debug.
I started in this configuration:
No Pican installed on CAN bus
This is the code for the two feathers:
SENDING
RECEIVE ONLY:
Without the pican hooked up this is what happens
putty output from send (left) // receive (right)
Connecting the pican and having it read the messages from the bus.
works as intended
photo of pican attached
What the pican is doing is simply reading the messages from the bus. without the pican attached the example programs provided on https://github.com/adafruit/Adafruit_CircuitPython_MCP2515/tree/1.1.2/examples do not work at any baudrate. With the pican attached and reading from the bus they work at 1000000 baud.
The text was updated successfully, but these errors were encountered: