Re: Hardware Abstraction Layer - Rev 0.01
>
> 2) There are only two types of I/O, analog and digital.
> Digital values are either TRUE or FALSE. A "bit" data
> type is typedef'ed for digital data:
>
> typedef enum { FALSE = 0, TRUE = 1 } bit;
>
> (C++ defines a "bool" type, but I'm not sure it is
> supported in C. If it is, it would be better than
> creating a custom type.) "bit" values occupy at
> least one byte - no packing is done at the HAL level.
> This prevents problems when two threads try to modify
> different bits in the same byte.
I recommend using "char" for boolean's.
A C++ bool will be 1 byte but an enum as you
have above will be 4 bytes. But the type char is completely
unambigous. Defining your own version of TRUE, FALSE and bool
is something I see too many programs do. The problem is that there is no
way too know your definition won't conflict with someone elses that
is included by some header file perhaps very indirectly. Even if you
successfully
compile you can never be certain that some future version of a header file
you don't even care about will redefine it. I always just use 0 and 1
directly in my
code and have given up trying to alias these to FALSE and TRUE.
>
> Analog values are represented as "doubles". Most of the
> code that manipulates these values will be running in a
> thread that already uses floating point, so there will
> be no performance hit for saving/restoring the FP state.
> Drivers that use a faster thread (for example software
> step/direction) could convert from float to int in the
> slow thread, and run the fast thread entirely with
> fixed point. (But they don't have to, the decision is
> made by the driver implementer.)
>
>
> Data Structures:
>
> HAL Runtime Data:
>
> EMC Side Data:
>
> /* structure containing all EMC side variables for an abstracted
> motion axis */
> typedef struct
> {
> double PosFb; /* input: position feedback, in
> counts */
> double VelCmd; /* output: velocity command, in
> counts/second */
> bit Home; /* input: true means home switch
> tripped*/
> bit LoLim; /* input: true means low limit
> switch tripped */
> bit HiLim; /* input: true means high limit
> switch tripped */
> bit Fault; /* input: true means amp has
> faulted */
> bit Clamp; /* output: true means axis should
> be clamped */
Does this mean clamp velocity, voltage, or position? Either way would we
need some max value to clamp it to?
>
> bit Enable; /* output: true means amp should
> be enabled */
> /* Anything else? */
> } HAL_AXIS;
>
> There would be one of these for each axis. There would also be
> structures for
> the spindle(s), and variables or structures for other I/O such as
> coolant,
> lube, toolchangers, etc.
>
> HW Side Data:
>
> /* structure containing all HW side variables for a printer port */
> /* defined in the printerport driver and present only when that
> driver is loaded */
> typedef struct
> {
> bit Pin1; /* output: true drives pin 1 hi */
> bit Pin14; /* output: true drives pin 14 hi */
> bit Pin16; /* output: true drives pin 16 hi */
> bit Pin17; /* output: true drives pin 17 hi */
> bit Pin2; /* output: true drives pin 2 hi */
> bit Pin3; /* output: true drives pin 3 hi */
> bit Pin4; /* output: true drives pin 4 hi */
> bit Pin5; /* output: true drives pin 5 hi */
> bit Pin6; /* output: true drives pin 6 hi */
> bit Pin7; /* output: true drives pin 7 hi */
> bit Pin8; /* output: true drives pin 8 hi */
> bit Pin9; /* output: true drives pin 9 hi */
> bit Pin10; /* input: true when pin 10 is hi */
> bit Pin11; /* input: true when pin 11 is hi */
> bit Pin12; /* input: true when pin 12 is hi */
> bit Pin13; /* input: true when pin 13 is hi */
> bit Pin15; /* input: true when pin 15 is hi */
> } DRV_PPBITS;
>
> There would be a data structure for each driver loaded. The
> structure would
> vary depending on the I/O mix provided by the driver.
>
> HAL Init Data:
>
> Link Data:
>
> /* structures used to establish a link between an EMC side
> variable and a HW side variable */
> typedef struct
> {
> double *src; /* pointer to data source */
> double *dst; /* pointer to data destination */
> } HAL_LINK_DBL;
>
> typedef struct
> {
> bit *src; /* pointer to data source */
> bit *dst; /* pointer to data destination */
> bit invert; /* true means an inverting link */
> } HAL_LINK_bit;
>
> /* arrays of links, filled in from ini file */
>
> HAL_LINK_DBL hal_output_links_dbl[MAX_LINKS_DBL];
> HAL_LINK_BIT hal_output_links_bit[MAX_LINKS_BIT];
> HAL_LINK_DBL hal_input_links_dbl[MAX_LINKS_DBL];
> HAL_LINK_BIT hal_input_links_bit[MAX_LINKS_BIT];
>
> Driver Function pointers:
>
> An array of pointers to each driver's runtime code
>
>
> Sqeuence of operation:
>
> 1) Hardware interrupt occurs (either system timer, or hardware device)
> 2) Run through both output link arrays, copying data from EMC side to
> HW side.
> 3) Run through driver function pointer array, calling driver runtime
> code.
> 4) Driver runtime code copies output data from HW side structs to the
> actual hardware.
> 5) Driver runtime code copies input data from the actual hardware to
> the HW side structs.
> 6) Driver runtime code returns.
> 7) Run through both input link arrays, copying data from HW side to
> EMC side.
> 8) End of HAL code, begin executing servo loop code (emcmot).
>
> MAJOR ISSUES:
>
> The runtime stuff is pretty simple, in fact I coded it in less than an
> hour.
> Init is the hard part. The drivers must export the names and locations
> of their runtime data in a way that allows the ini file to specify links.
> Links might look like this in the ini file:
The INI file program almost definitely has to be read in a user space app.
This means either each each HAL implementation comes with two components
a real time driver and a corresponding non realtime app that reads and
parses the INI file and sends data appropriate for that HAL down to
realtime app via shared memory or fifo.
Or we always copy the entire INI file down and have each HAL parse the
INI data now loaded into memory. My preference would probably be for the
first option since the less
code that runs in realtime where debugging is harder and mistakes are
more likely to halt your system the better.
>
>
> [INLINKS]
> axis[0].pos_fb = stg[1].chan[2].encoder
> axis[0].hi_limit = parallelport[0].Pin11
> axis[0].lo_limit = parallelport[0].Pin11
> axis[0].home = !stg[1].digio[20]
>
> [OUTLINKS]
> stg[1].chan[2].dac = axis[0].vel_cmd
> parallelport[0].Pin3 = axis[0].enable
>
> Note in the INLINKS section that both the high limit and
> low limit are linked to the same input, and the home input
> is low true, which generates an inverting link.
>
> There is also no reason why a link has to go from the HW
> side to the EMC side, or vice-versa. A link from one EMC
> variable to another would be perfectly legal, as would a link
> from one HW side variable to another.
>
> In fact, a PLC could be loaded just like a driver. It would
> export a number of bits that would be coils and contacts
> in it's ladder logic. Links would connect the coils and
> contacts to EMC side and/or HW side variables as needed.
>
> I'm learning more about the ini file and the functions that
> manipulate it, but I'm not ready to propose a detailed
> mechanism to get from the list of links above to a
> completely filled in set of link arrays. I just wanted to
> post this to get other people looking at it. Please
> review and let me know what you think.
>
> John Kasunich
>
--
--------------------------------------------------
Will Shackleford
NIST
100 Bureau Dr. Stop #8230
Gaithersburg, MD 20899
(301) 975-4286
Please do not send me Microsoft formatted documents.
They frequently contain viruses and discourage fair
competition and open standards.
I will ignore any email that contains them unless
absolutely necessary.
-------------------------------------------------
Date Index |
Thread Index |
Back to archive index |
Back to Mailing List Page
Problems or questions? Contact