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"

Attachment: 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

Reply via email to