bakerstu / openmrn

OpenMRN (Open Model Railroad Network)
BSD 2-Clause "Simplified" License
57 stars 28 forks source link

Minimum working example for PCA9685 #341

Open elstanto opened 4 years ago

elstanto commented 4 years ago

Hello. I'm trying to deploy a node using an STM32F303RE (nucleo board at the moment but then custom PCB), using both PCA9685 and MCP23017 (for input). I can't find any examples of the PCA9685 driver being used - would it be possible to see one please, unless I have missed it?

Also, has anyone implemented the stm32 VCP/CDC driver for onboard USB to CAN, rather than using a USB-UART adapter? I couldn't find it in this code so have a second bare nucleo running https://github.com/cvra/CAN-USB-dongle-fw, but it would be nice to use common openmrn code on both.

balazsracz commented 4 years ago

Hi,

For the PCA9685 / MCP23017 combo, @SpeedTxn was working on such a node and has a PR with a pretty complex example. https://github.com/bakerstu/openmrn/pull/93/files#diff-48e9c415bb0954ed6356aa846186e63b I believe the example worked at the time it was created, but i'm not sure about the current state. Given that it uses the abstraction for i2c, the same main.cxx should work on the STM32F303 as well so long as you create the I2C drivers in HwInit.cxx and set up the pin mux correctly. I have 23017's but no pc9685 so hard for me to test. But if you make a PR (including in your own repo) and tag me for review, I'll be happy to take a look at your code. There are some minor changes in @SpeedTxn 's PR that should be applied to the PCA9682 driver in freertos_drivers/common independently of whether he intends to merge or abandon his code -- I recommend you to patch those maybe into a separate PR and submit it independently. We already did so with the MCP23017 driver's diffs.

As for USB-CDC, this was not a very high priority because most nucleo boards do not have a natively connected USB port. I used to have aan stm32 USB driver but it was based on a prior version of ST's middleware (PLIB) which is no longer supported. There is something in the Stm32Cube it seems. I have had significant trouble trying to incorporate vendor USB code in the past due to most of them having some flow control bugs, so I would not assume adding this is easy. I might be able to prototype something during the holidays on an F7 nucleo that I have which comes with onboard USB.

I would like to caution you about something though. Building a USB-CAN or adding a USB port to a model railroad IO device comes with a significant risk when not engineered with galvanic isolation. Without isolation you have to force the ground of your model railroad to be the same as the ground of your computer. I would really caution against doing that; in a few situations it is okay (e.g. a laptop running from battery), but in a lot of situations that look very similar to that (e.g. laptop plugged into a power supply) it is not okay anymore and could blow up / set on fire pretty much anything, from your command station to the booster to the computer etc.

Adding isolation on the USB side is a huge pain. Adding isolation on the CAN side is more possible. I recommend just buying the USB-CAN adapter from RR-CirKits, because we know very well that it is isolated and safe to use.

hth Balazs

elstanto commented 4 years ago

Thanks balazs,

Sure, I can have a look at those. I noticed the MCP driver is different (i.e. init takes an i2c instance rather than device name). Is there a preferred way for this to be standardised? I'd also like to add separate functions for the led control register and the pwm, for applications where people don't want to write pwm counts to toggle them on/off - e.g. using pwm for brightness correction only.

So, we are actually using this to update a large restored signalling control panel which currently uses ~70 TowerPro loconet units. We are streamlining the system with new eurocard boards based around openlcb and either 64 high current pwm outputs or 64 inputs (both 24 V). The existing system has the level shifters and drivers all on separate boards and uses a lot of space which we need for additions. We would like to include the usb to can adapter on the backplane (with swappable ethernet to can), so we have become familiar with isolation 😄

Another issue, which I'll post on the openlcb list, is that we want to cards swappable without PC use by our volunteers. The idea is to have selector switches on the front to assign a local ID. However, from what I've seen of openLCB (I'm a newbie) that would require all the 70 CDIs to be stored on each card so they could be selected - i.e. changing the node ID wouldn't be enough. Unless we wrote a jmri script that detected/polled new cards and checked the CDI, automatically downloading if there was a discrepancy. Any thoughts?

Many thanks!!

On Thu, 12 Dec 2019, 4:18 pm Balazs Racz, notifications@github.com wrote:

Hi,

For the PCA9685 / MCP23017 combo, @SpeedTxn https://github.com/SpeedTxn was working on such a node and has a PR with a pretty complex example. https://github.com/bakerstu/openmrn/pull/93/files#diff-48e9c415bb0954ed6356aa846186e63b I believe the example worked at the time it was created, but i'm not sure about the current state. Given that it uses the abstraction for i2c, the same main.cxx should work on the STM32F303 as well so long as you create the I2C drivers in HwInit.cxx and set up the pin mux correctly. I have 23017's but no pc9685 so hard for me to test. But if you make a PR (including in your own repo) and tag me for review, I'll be happy to take a look at your code. There are some minor changes in @SpeedTxn https://github.com/SpeedTxn 's PR that should be applied to the PCA9682 driver in freertos_drivers/common independently of whether he intends to merge or abandon his code -- I recommend you to patch those maybe into a separate PR and submit it independently. We already did so with the MCP23017 driver's diffs.

As for USB-CDC, this was not a very high priority because most nucleo boards do not have a natively connected USB port. I used to have aan stm32 USB driver but it was based on a prior version of ST's middleware (PLIB) which is no longer supported. There is something in the Stm32Cube it seems. I have had significant trouble trying to incorporate vendor USB code in the past due to most of them having some flow control bugs, so I would not assume adding this is easy. I might be able to prototype something during the holidays on an F7 nucleo that I have which comes with onboard USB.

I would like to caution you about something though. Building a USB-CAN or adding a USB port to a model railroad IO device comes with a significant risk when not engineered with galvanic isolation. Without isolation you have to force the ground of your model railroad to be the same as the ground of your computer. I would really caution against doing that; in a few situations it is okay (e.g. a laptop running from battery), but in a lot of situations that look very similar to that (e.g. laptop plugged into a power supply) it is not okay anymore and could blow up / set on fire pretty much anything, from your command station to the booster to the computer etc.

Adding isolation on the USB side is a huge pain. Adding isolation on the CAN side is more possible. I recommend just buying the USB-CAN adapter from RR-CirKits, because we know very well that it is isolated and safe to use.

hth Balazs

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/bakerstu/openmrn/issues/341?email_source=notifications&email_token=AAK5N5VL7KMG4M3OXTOCBATQYJP67A5CNFSM4JZXONF2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEGXGFTA#issuecomment-565076684, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAK5N5TGWGB3ST6DZTHTTP3QYJP67ANCNFSM4JZXONFQ .

balazsracz commented 4 years ago

Thanks balazs, Sure, I can have a look at those. I noticed the MCP driver is different (i.e. init takes an i2c instance rather than device name). Is there a preferred way for this to be standardised?

I2C application drivers should always work by device name (string), but we need to keep in mind that executing ::open(name,...) calls is not possible in the constructor. So there needs to be an init(i2c_name) call which does that. If any driver takes an I2C* or inherits from I2C, that needs to be fixed.

I'd also like to add separate functions for the led control register and the pwm, for applications where people don't want to write pwm counts to toggle them on/off - e.g. using pwm for brightness correction only.

There was a bit of work done in the servo support area which might be useful as a starting point. The ServoConsumer uses a user-configured on and off tick count which comes from persistent memory, then a pair of events to toggle between the two states at run time (usable like a turnout from JMRI).

So, we are actually using this to update a large restored signalling control panel which currently uses ~70 TowerPro loconet units. We are streamlining the system with new eurocard boards based around openlcb and either 64 high current pwm outputs or 64 inputs (both 24 V).

Is the plan to have the node's MCU on the card or on the backplane? How many card slots do you have in the backplane? Does every card slot need to be both input and output capable?

The existing system has the level shifters and drivers all on separate boards and uses a lot of space which we need for additions. We would like to include the usb to can adapter on the backplane (with swappable ethernet to can), so we have become familiar with isolation

for USB to CAN you only really need it if you are physically there with a computer to be plugged in. So it is equivalently enough to have a single RJ45 plug (having a tee of the CAN-bus) and when you go there with a laptop, you bring your LCC-Buffer and plug in with a short cable. CAN does allow T shaped taps if they are short.

Ethernet to can is harder. OpenMRN has code for a Tiva129 chip that works, that chip is quite a challenge to solder by hand though (0.4mm pitch 100 pin). If you have space on the backplane you could put down the headers for plugging in a tiva devkit board (. The $12 Tiva launchpad board can do USB-CAN and the $20 can do Eth-CAN. They are pin compatible as much as the CAN bus and power goes, so a single isolation region and an ISO1050 on the backplane would do the trick.

OpenMRN supports both of these boards, including the CDC driver.

Another issue, which I'll post on the openlcb list, is that we want to cards swappable without PC use by our volunteers. The idea is to have selector switches on the front to assign a local ID.

Based on the previous question: do you have the node's MCU on the card?

However, from what I've seen of openLCB (I'm a newbie) that would require all the 70 CDIs to be stored on each card so they could be selected - i.e. changing the node ID wouldn't be enough. Unless we wrote a jmri script that detected/polled new cards and checked the CDI, automatically downloading if there was a discrepancy. Any thoughts? Many thanks!!

elstanto commented 4 years ago

Hi,

We are planning to have one MCU per card, as we would like to be able to use cards individually in future for smaller systems. The backplane will be modular, so for a single card out of the rack a single backplane pcb can be attached to act as a breakout and usb/eth-to-can adapter. We need a constant PC connection as the interlocking (the point of the installation) is all simulated in JMRI. Cards will either be input or output, as I don't have enough space to put the option of drivers and isolating buffers on each card. But that is fine with out setup. In future I might do one with a mixture if we use single cards somewhere.

I got the PWM chip working easily with the code you linked. However, I'm having a lot of issues with the MCP code. The new code in the master branch works, but I can't get any registers written with the code in bakerstu MCP branch. I'll do some more debugging. I sorted the interrupt code converting from Tiva to ST, but it is more of a pain as the enabling calls aren't named in a way which is friendly to build from port and pin arguments.

So if I used the latter of your options for the "rotary switch config" (actually it was hardwired backplane, I got confused as we're using rotary switches for local testing to force-feed outputs), then how would the CDI work? are there calls in OpenMRN to force the eventid during startup?

balazsracz commented 4 years ago

You only have one backplane in your entire layout ever? (the one at your computer?)

For the MCP23017 driver, it appears that we have written two implementations of the driver independently; one by Stuart, then another one by myself quite a bit later. Given that the second implementation is merged to master, it is more likely it will work -- as you say. There isn't any good reason for you to need the other implementation if this one works.

We should prioritize to get what you need to the master branch. If you have time, please take any changes you needed from the txn-plant branch, commit it to a new branch and submit a PR with it.

As for hardwired event configurations, in that case you don't need a CDI at all. Your events would not be configured by CDI, but rather... hardwired. Here is an example of what my code looks like where I do that: https://github.com/balazsracz/openmrn_cue/blob/master/cs/targets/acc.tiva.3/main.cxx#L111 You will need to adjust this somewhat, because the base event ID will not be a compile-time constant for you, but you could write a static initializer that peeks at the GPIO lines at startup.

elstanto commented 4 years ago

Sorry - forgot some info. Each rack is 12 cards, about 6 racks. Each stackable backplane PCB (one card width) has power supply connections, 2x4 RJ45 block for IO (same used by 19" network routers/switches), and CAN through which also tees to an expansion header which takes the USB or eth to CAN adapter. The idea would be one adapter per installation, so most racks just chain off the CAN out from the last one. Yes we could use an rr-circuits interface but I'll keep the expansion header on so we can do our own :)