I am working on an EMC2 interface for the Mesa buffered SPI Hostmot2 component. At this point the aim is to support the 7i65 octuple servo interface (8 DAC channels, 8 ADC channels 8DO 4 DI) I am trying to generalise it, and at the moment the plan is to handle the daughterboard-specific stuff in a comp module with a generic interface in the Hostmot2 driver.
_Background_ 1) The Hostomot2 driver. Typically this scans the bitfile and determines which functions are present, it then passes a *hostmot2_t pointer to each sub-driver, and the sub driver claims the GPIO pins on the board, creates the HAL pins and links internal storage to individual registers on the FPGA card using a function called TRAM. (AFAIK this is not actually using the translation RAM at the moment, but will, in future, allow DMA). Included in the *hostmot2_t structure is a pointer to a function that abstracts the low-level communications between the driver and the various types of cards, (PCI, PCIe and Parallel). On multi-card systems is also determines _which_ board the sub-function exists on. So, without the *Hotmot2_t pointer the sub-drivers can't communicate and don't know which card to talk to anyway. This pointer is the key to all hostmot2 data and hardware access. It is "pushed" by the main driver to its sub-functions. Every servo cycle the Hostmot2 main driver runs a TRAM read, transferring data from the registered FPGA registers, calls the process_tram_read function of each sub-driver to handle the data, convert it into values on HAL pins etc, it then calls prepare_tram_write for each sub-driver and then updates the registers via a TRAM transfer. It is possible I have that sequence reversed. What this means is that all the TRAM registers get read or written once every servo cycle. It is possible to write to individual registers outside this process, but in the future that will break DMA. 2) The Buffered SPI function. This function uses 16 write registers on the FPGA to support 16 possible SPI frame types. (ie, bit lengths, address codes etc). The registers all share the same 16-element 32-bit transmit FIFO, with the register being written to determining which frame structure the data is transmitted with. _Previous Discussion_ There is a Wiki page which attempted to define an SPI protocol inside the HAL "all communications by pins" paradigm http://wiki.linuxcnc.org/emcinfo.pl?SPI_Sub-Driver_For_Hostmot2 I originally started to work within this framework, but it rapidly became clear that is was unworkable. Taking the example of the 7i65 it would have required 46 HAL pins to be correctly connected between the 7i65 sub-driver and the Hostmot2.BSPI sub-driver for each card. Whilst this might be possible, there was a further problem that the sub-driver does not know at driver-load time which BSPI registers will be used. Often many successive transfers will occur through the same BSPI register, for example 8 x ADC reads from the same 8-channel ADC device. Registering 16 reads and writes for each of the frames on a "just in case" basis is not an option, as the FIFO is only 16 entries deep, so the first, possibly unused, channel will fill the FIFO every time before the other frames get a chance. _Possible Structures_ 1) What I have coded (and might actually be working, I don't actually have the hardware) The hostmot2.bspi sub-driver claims the GPIO pins as normal, kmallocs and hal_mallocs storage as normal, and sets a hm2.bspi.instance[n].name string to a unique value (which is reported on stdio, and might also become a dummy HAL pin name in a future iteration). It doesn't create any HAL pins. A new function inside the hostmot2 driver called hm2_get_bspi searches through all Hostmot2 instances (in effect, through all installed cards) for a bspi instance with a matching name, and returns a *hostmot2_t pointer and the index of the bspi driver instance. The mesa_7i65.comp receives a bspi instance name as a modparam, calls the hm2_find_bspi() function and uses the returned pointer to register the required registers with the TRAM and to perform the required low-level reads and writes to configure the channels etc. It also creates suitable HAL pins. To make this possible I needed to make the hm2_register_tram_regions() function handle being called repeatedly with extra data each time because there is no way to know when the hal file has finished adding new devices. Currently the mesa_7i65.comp only exports one function per instance which would typically be added to the thread between the hm2.read and hm2.write functions for the respective fpga card. In the future it might export 3, read, write and send. (send would be the function that sends out the data transmit requests). However this would be a rather artificial distinction given the once-per-thread nature of the TRAM transfers. 2) Hide the TRAM from the .comp author. It would be possible to move the call to the hm2_find_bspi() function into the hm2_bspi sub-driver. That sub-driver would export configure_channel(index, specification) and add_read(index, &buffer), add_write(index, &buffer) etc functions for use by the comp-based driver. This could probably be made more robust, but at the expense of flexibility. I am quite likely to make this change. 3) Add a hal_pointer_t pin. It would be possible to export a pointer to a specific bspi instance on a HAL pin. You could even do it on a generic u32 pin, but the consequences of mis-connection seem potentially problematical. To be any use for low-level writes and tram registration the instance would need to contain a pointer to its parent *hostmot2_t. This seems to be reasnably common elsewhere, though. Ideally this would be a new type of HAL pin, with both 32 bits of pointer and a related "type code" which would allow HAL to raise an error if the hal file attempted to net an encoder instance to an spi pointer pin, for example. One significant drawback with this is a problem with what happens when. Generally hal modules initialise themselves at load-time, but with this scheme they wouldn't be able to initialise until they have been netted to a pointer pin, which effectively means that they would have to initialise the first time they were called by their thread, at which point everything is "live" and it might well be too late to add anything to the TRAM. Allowing hal file command sequences like: net p1 hm2_5i23.0.bspi.01.ptr <=> mesa_7i65.0.bspi-ptr run mesa_7i65.0.init Might be a solution, but seems a very major change to support (currently) zero devices. To give a feel for the look of an SPI driver in comp I have attached an (unfinished, largely untested, never yet seen hardware) 7i65 driver. I hope this gives enough background as to why the normal way won't work. The purpose of this epic post is to stimulate discussion of alternative structures that might work better, or be more generic, or nicer. -- atp "Torque wrenches are for the obedience of fools and the guidance of wise men"
mesa_7i65.comp
Description: Binary data
------------------------------------------------------------------------------ Xperia(TM) PLAY It's a major breakthrough. An authentic gaming smartphone on the nation's most reliable network. And it wants your games. http://p.sf.net/sfu/verizon-sfdev
_______________________________________________ Emc-developers mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/emc-developers
