|
|
| Author |
Message |
Paul Lamar
Joined: 14 May 2010
Posts: 46
|
|
Posted: 10 July 2010, 19:15 PM Post subject: How to read in a byte |
|
|
This might be a really stupid question.
How do I read a byte in from a port name?
Paul Lamar
|
|
| Back to top |
|
 |
dkinzer Site Admin
Joined: 03 Sep 2005
Posts: 2593
Location: Portland, OR
|
|
Posted: 10 July 2010, 20:11 PM Post subject: Re: How to read in a byte |
|
|
| Paul Lamar wrote: | | How do I read a byte in from a port name? | To manipulate the full width of a port you must refer to the appropriate I/O register. For example, to read the logic value present at the pins of PortD you use Register.PIND.
On mega-based devices, each I/O port comprises three registers: PINx, PORTx and DDRx, where x is replaced by a port letter, e.g. A, B, C, etc. The bits of DDRx (Data Direction Register) control whether the corresponding pin is an input (zero) or an output (one). The bits of the PORTx register control two different things depending on whether the corresponding pins is configured to be an input or an output. If an input, the PORTx bit enables the pullup resistor and if an output it controls the state of the pin. Lastly, the PINx register provides a way to read the logic value present on the pins, irrespective of whether the individual pins are inputs or outputs. On newer mega devices, writing a 1 to a bit of the PINx register will toggle the state of the corresponding PORTx bit.
The information about the port registers can be found in the datasheet for the particular mega processor used on your ZX device. The datasheets are available on the Downloads Page as well as at the Atmel site.
|
|
| Back to top |
|
 |
Paul Lamar
Joined: 14 May 2010
Posts: 46
|
|
Posted: 11 July 2010, 10:42 AM Post subject: |
|
|
Thanks Don.
I notice you discuss Register.PIND starting on page 63 of your ZBasic Language Reference Manual.
Could you give me an example of reading in a byte for PORTA using Register.XXXXX on
the 1280n?
I understand the concept of a data direction register. I just don't know how to set things up in ZBasic.
What do you mean by the term "control program"?
Which ports will affect the "control program" if modified?
See the attachement.
Paul Lamar
| Description: |
|
 Download |
| Filename: |
ZX-1280n-Registers.jpg |
| Filesize: |
81.92 KB |
| Downloaded: |
1630 Time(s) |
|
|
| Back to top |
|
 |
dkinzer Site Admin
Joined: 03 Sep 2005
Posts: 2593
Location: Portland, OR
|
|
Posted: 11 July 2010, 15:17 PM Post subject: |
|
|
| Paul Lamar wrote: | | Could you give me an example of reading in a byte for PORTA using Register.XXXXX on the 1280n? |
| Code: | Dim b as Byte
b = Register.PinA |
| Paul Lamar wrote: | | I understand the concept of a data direction register. I just don't know how to set things up in ZBasic. | If you wanted to make all 8 bits of PortA outputs, you could call PutPin() eight times or you could simply write | Code: | | Register.DDRA = &Hff | Similarly, all 8 bits can be made inputs (the post-reset state) by writing zero to the DDR.
| Paul Lamar wrote: | | What do you mean by the term "control program"? Which ports will affect the "control program" if modified? | The control program refers to the interpreter that runs on VM devices. The smaller VM devices store the user program in an external EEPROM that is accessed via the SPI bus. On these devices, if you were to change the direction of the I/O pins used for the SPI interface you could prevent the SPI accesses from working correctly.
This is less of a problem on native mode devices but it is still possible to inadvertently change the state of I/O pins that are needed for other purposes. For example, if you call OutputCapture() in one task and then in another task you inadvertently change the direction of the I/O pin used by OutputCapture() you will cause it to fail. What this means is that you must carefully consider the effect of manipulating the registers directly to avoid changing bits that you didn't intend to change.
Note that the SetBits() subroutine can be used to manipulate a subset of the bits in a register. For example, if you wanted to set the direction of the four least significant bits of PortA while leaving the upper four bits unchanged you could write: | Code: | | Call SetBits(Register.DDRA, &H0F, &H05) | This would make bits 0 and 2 outputs and bits 1 and 3 inputs. The advantage of using SetBits() is that it guarantees that the required read-modify-write operation is atomic. You could implement the same functionality thusly: | Code: | Atomic
Register.DDRA = (Register.DDRA And &HF0) Or &H05
End Atomic |
|
|
| Back to top |
|
 |
Paul Lamar
Joined: 14 May 2010
Posts: 46
|
|
Posted: 11 July 2010, 17:44 PM Post subject: |
|
|
Thanks Don,
Perhaps you could extend ZBasic and write a PEEK(Port) and POKE(Port) by first reading
what the port set up is, save it and restore that after the instruction executes. It will add time
no doubt but a warning to that effect in the manual would be OK.
Paul Lamar
|
|
| Back to top |
|
 |
dkinzer Site Admin
Joined: 03 Sep 2005
Posts: 2593
Location: Portland, OR
|
|
Posted: 11 July 2010, 18:41 PM Post subject: |
|
|
| Paul Lamar wrote: | | Perhaps you could extend ZBasic and write a PEEK(Port) and POKE(Port) by first reading what the port set up is, save it and restore that after the instruction executes. | I don't understand the functionality that you would like to have added. What, in general terms, would PEEK(port) and POKE(port) do and can you give examples of using them to accomplish specific tasks?
|
|
| Back to top |
|
 |
Paul Lamar
Joined: 14 May 2010
Posts: 46
|
|
Posted: 11 July 2010, 19:20 PM Post subject: |
|
|
There are some hardware devices in the world that communicate with a computer
8 bits at a time through a parallel interface. The best and most widely used is
the famous Centronics printer interface. Hard drives used to be parallel before SATA
although hard drives made little sense as the data had to be written and read one bit
at a time anyway unless one was using 8 sides of four magnetic disks.
Arguably a parallel interface is easier and quicker than a serial interface where data goes out one bit at a time. It is certainly easer for the BASIC programmer to PEEK or POKE a port or memory location as a lot of data manipulation is done 8 bits at a time. A person designing such a parallel device has an easier time of it rather than adding the hardware required to serialise data that started life as parallel data.
There are two types of processors. Those that handle I/O as just another
memory location and those that use dedicated registers for I/O. The first example is the
Motorola, Mos Technology (Early Apple) and Intel processors and those that use dedicated registers. such as (apparently) the Atmel perhaps among others.
In the first group the ports were in general automatically bi directional as are memory locations. These used a read write line that goes along with the PEEK or POKE. DDR's were not always necessary but could be accommodated. This was called memory map I/O.
Paul Lamar
|
|
| Back to top |
|
 |
GTBecker
Joined: 18 Jan 2006
Posts: 472
Location: Cape Coral
|
|
Posted: 11 July 2010, 19:54 PM Post subject: Ouch! |
|
|
Paul, forgive me, please; this will sting a little.
Did you build and engage a time machine in 1980 - and inadvertently return to the future? Where have you been for the last 30 years?
To invite someone to implement the likes of a Centronics port today is bizarre. To lecture on memory mapping is insulting. Although machines remain massively parallel within the chip, speed has replaced most external parallel buses. Serializing parallel data today is easy and cheap - and done onboard the processors; we no longer need 40-pin 8250 UARTs to do it, nor the FIFO, since memory abounds.
I am 63; I suspect you are near that, and I still respect my elders. I loved the 1401 I started on and I still have my IBM printer rule and flowchart template, but I no longer use them; time has elapsed. Truly, have you only recently rejoined technology?
|
|
| Back to top |
|
 |
Paul Lamar
Joined: 14 May 2010
Posts: 46
|
|
Posted: 11 July 2010, 21:03 PM Post subject: |
|
|
No insult intended Don.
I am sorry you see it that way.
It does not sting as I respect differences of opinion.
You have not changed my mind.
Paul Lamar
|
|
| Back to top |
|
 |
Paul Lamar
Joined: 14 May 2010
Posts: 46
|
|
Posted: 11 July 2010, 21:22 PM Post subject: |
|
|
Here is another project I am working on.
Note the anything I/O card is massively parallel.
These boards are widely used world wide to control NC
machine tools using EMC software
Paul Lamar
| Description: |
|
| Filesize: |
76.23 KB |
| Viewed: |
2591 Time(s) |

|
| Description: |
|
 Download |
| Filename: |
Mesa-7i33.jpg |
| Filesize: |
94.38 KB |
| Downloaded: |
1621 Time(s) |
| Description: |
|
 Download |
| Filename: |
Mesa-5i20.jpg |
| Filesize: |
96.03 KB |
| Downloaded: |
913 Time(s) |
| Description: |
|
 Download |
| Filename: |
control-block-diag5S.jpg |
| Filesize: |
66.27 KB |
| Downloaded: |
1621 Time(s) |
|
|
| Back to top |
|
 |
dkinzer Site Admin
Joined: 03 Sep 2005
Posts: 2593
Location: Portland, OR
|
|
Posted: 11 July 2010, 22:07 PM Post subject: |
|
|
| Paul Lamar wrote: | | No insult intended Don. | Perhaps you're responding to a reply from Tom.
As far as the PEEK and POKE are concerned, if the 8-bit port remains configured as all inputs or all outputs then simply referring to Register.PINx or Register.PORTx, respectively is all that is needed to read a byte from or write a byte to the port. If you need the port to be bi-directional, then it is only slightly more involved. | Code: | ' to write a port
Register.DDRA = &HFF ' set the direction
Register.PortA = val
' to read a port
Register.DDRA = &H00 ' set the direction
Register.PortA = &H00 ' turn off pullups
val = Register.PinA |
I can't think of a good way to encapsulate these in a simple subroutine and function to generalize them using ZBasic statements only but it could be done for most mega-based native mode devices using some C code like this: | Code: | '-----------------------------------------------------------------------
'
' C routines to read and write ports. These do not work on older
' mega devices (e.g. the mega128) because the PIN, DDR and PORT
' registers are not sequential nor do they work on the xmega devices
' because they have a different I/O port structure.
'
' On newer mega devices, the three registers associated with an I/O
' port are arranged sequentially: PINx, DDRx and PORTx.
'
#c
// low-level ZX Library routine to get the base address of a port
uint8_t *getPortAddr(uint8_t idx);
// function to make a port all outputs and write a value to it
void
_writePort(uint16_t portIdx, uint8_t val)
{
// get the port address, check for a valid port
uint8_t *addr = getPortAddr(portIdx);
if (addr != NULL)
{
addr[1] = 0xff; // make all bits outputs
addr[2] = val; // write the PORTx register
}
}
// function to make a port all inputs, turn off the pullup resistors
// and then read the PINx register.
uint8_t
_readPort(uint16_t portIdx)
{
uint8_t val = 0;
// get the port address, check for a valid port
uint8_t *addr = getPortAddr(portIdx);
if (addr != NULL)
{
addr[1] = 0; // make all bits inputs
addr[2] = 0; // turn off pullup resistors
val = addr[0]; // read the PINx register
}
return(val);
}
#endc
'-----------------------------------------------------------------------
' an enumeration to define the port index values: A=0, B=1, etc.
Enum PortType
PortA = 0
PortB
PortC
PortD
' add other ports as needed
End Enum
' declare the ZBasic interface to the C functions
Declare Function ReadPort(ByVal port as PortType) as Byte Alias "_readPort"
Declare Sub WritePort(ByVal port as PortType, ByVal val as Byte) Alias "_writePort"
Dim b as Byte
Sub Main()
b = ReadPort(PortA)
Call WritePort(PortB, &H55)
End Sub |
|
|
| Back to top |
|
 |
Paul Lamar
Joined: 14 May 2010
Posts: 46
|
|
Posted: 11 July 2010, 22:18 PM Post subject: |
|
|
One other thing Don and then I'll shut up.
It took 2.5 usec to set pin 12 low and 2.5 usec to set it high.
Basically a parallel operation.
However it took 12.5 usec to send out one ASCII character
through the USB serial port using debug.print.
Now if you had half a dozen USB ports on the 1280n board I might change my
mind There is only one and I have half a dozen things I want to control.
I rest my case.
Paul Lamar
| Description: |
|
 Download |
| Filename: |
serial-port-test.jpg |
| Filesize: |
66.86 KB |
| Downloaded: |
1619 Time(s) |
| Description: |
|
 Download |
| Filename: |
IMG_0662.JPG |
| Filesize: |
60.86 KB |
| Downloaded: |
1621 Time(s) |
|
|
| Back to top |
|
 |
stevech
Joined: 23 Feb 2006
Posts: 688
|
|
Posted: 12 July 2010, 0:46 AM Post subject: |
|
|
| that 2.5uSec is in the native mode (not VM)?
|
|
| Back to top |
|
 |
Paul Lamar
Joined: 14 May 2010
Posts: 46
|
|
Posted: 12 July 2010, 2:04 AM Post subject: |
|
|
The compiler. Not the interpreter.
Paul Lamar
www.rotaryeng.net
|
|
| Back to top |
|
 |
Paul Lamar
Joined: 14 May 2010
Posts: 46
|
|
Posted: 13 July 2010, 21:08 PM Post subject: |
|
|
Thanks Don,
Worked like a charm.
It is at least ten times faster than the serial USB port because
if you comment out "val = Register.PINH" the scope trace
hardly changes. That means just taking a bit low and then high
takes at least 10 usec. while reading in 8 bits parallel probably
takes much less than one usec. I could do ten in a row
and see what happens but I am very very happy with less
than a usec.
This greatly simplifies my hardware on the sending end as no
need to serialise and handle the serial hand shaking.
Thanks for your help Don.
Paul Lamar
www.rotaryeng.net
| Description: |
|
 Download |
| Filename: |
peek-time-test.JPG |
| Filesize: |
53.49 KB |
| Downloaded: |
1619 Time(s) |
| Description: |
|
 Download |
| Filename: |
IMG_0663.JPG |
| Filesize: |
80.39 KB |
| Downloaded: |
1615 Time(s) |
| Description: |
|
 Download |
| Filename: |
IMG_0665.JPG |
| Filesize: |
56.55 KB |
| Downloaded: |
1616 Time(s) |
|
|
| Back to top |
|
 |
|