📄 chapter 7 pointers -- valvano.htm
字号:
however, need not observe this restriction, since they make no assumption about
the relative positions of objects. For example if <B>pt1</B> points into one
data array and <B>pt2</B> points into a different array, then comparing
<B>pt1</B> to <B>pt2</B> would be meaningless. Which pointer is larger would
depend on where in memory the two arrays were assigned.</FONT></P>
<P><B><I><FONT face=Helvetica,Arial><A name=FIFO></A>A FIFO Queue
Example</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">To illustrate the use of pointers we will
design a two-pointer FIFO. The first in first out circular queue (FIFO) is also
useful for data flow problems. It is a very common data structure used for I/O
interfacing. The order preserving data structure temporarily saves data created
by the source (producer) before it is processed by the sink (consumer). The
class of FIFO’s studied in this section will be statically allocated global
structures. Because they are global variables, it means they will exist
permanently and can be shared by more than one program. The advantage of using a
FIFO structure for a data flow problem is that we can decouple the source and
sink processes. Without the FIFO we would have to produce 1 piece of data, then
process it, produce another piece of data, then process it. With the FIFO, the
source process can continue to produce data without having to wait for the sink
to finish processing the previous data. This decoupling can significantly
improve system performance. </FONT></P>
<P><FONT face="Times New Roman,Times" size=2>GETPT</FONT><FONT
face="Times New Roman,Times"> points to the data that will be removed by the
next call to GET, and </FONT><FONT face="Times New Roman,Times" size=2>PUTPT
</FONT><FONT face="Times New Roman,Times">points to the empty space where the
data will stored by the next call to PUT. If the FIFO is full when PUT is called
then the subroutine should return a full error (e.g., V=1.) Similarly, if the
FIFO is empty when GET is called, then the subroutine should return an empty
error (e.g., V=1.) The </FONT><FONT face="Times New Roman,Times"
size=2>PUTPT</FONT><FONT face="Times New Roman,Times"> and </FONT><FONT
face="Times New Roman,Times" size=2>GETPT</FONT><FONT
face="Times New Roman,Times"> must be wrapped back up to the top when they reach
the bottom. </FONT></P>
<P> </P>
<P><IMG height=161 src="Chapter 7 Pointers -- Valvano.files/fifo.gif"
width=361></P>
<ADDRESS><FONT face="Times New Roman,Times">Figure 7-3: Fifo example showing the
PUTPT and GETPT wrap. </FONT></ADDRESS>
<P> </P>
<P><FONT face="Times New Roman,Times">There are two mechanisms to determine
whether the FIFO is empty or full. A simple method is to implement a counter
containing the number of bytes currently stored in the FIFO. GET would decrement
the counter and PUT would increment the counter. The second method is to prevent
the FIFO from being completely full. For example, if the FIFO had 100 bytes
allocated, then the PUT subroutine would allow a maximum of 99 bytes to be
stored. If there were already 99 bytes in the FIFO and another PUT were called,
then the FIFO would not be modified and a full error would be returned. In this
way if PUTPT equals GETPT at the beginning of GET, then the FIFO is empty.
Similarly, if PUTPT+1 equals GETPT at the beginning of PUT, then the FIFO is
full. Be careful to wrap the PUTPT+1 before comparing it to GETPT. This second
method does not require the length to be stored or calculated.</FONT></P>
<DIR>
<P><CODE>/* Pointer implementation of the FIFO */<BR>#define FifoSize 10 /*
Number of 8 bit data in the Fifo */<BR>#define START_CRITICAL() asm(" tpa\n staa
%SaveSP\n sei")<BR>#define END_CRITICAL() asm( ldaa %SaveSP\n tap")<BR>char
*PUTPT; /* Pointer of where to put next */<BR>char
*GETPT; /* Pointer of where to get next */<BR>/* FIFO is
empty if PUTPT=GETPT */<BR>/* FIFO is full if PUTPT+1=GETPT */<BR>char
Fifo[FifoSize]; /* The statically allocated fifo data */<BR>void InitFifo(void)
{unsigned char SaveSP;<BR> START_CRITICAL(); /* make
atomic, entering critical section
*/<BR> PUTPT=GETPT=&Fifo[0]; /* Empty when
PUTPT=GETPT */<BR> END_CRITICAL(); /* end critical
section */<BR>}<BR>int PutFifo (char data) { char *Ppt; /* Temporary put pointer
*/<B><BR></B>unsigned char SaveSP;<BR> START_CRITICAL();
/* make atomic, entering critical section
*/<BR> Ppt=PUTPT; /* Copy of put pointer
*/<BR> *(Ppt++)=data; /* Try to put data into fifo
*/<BR> if (Ppt == &Fifo[FifoSize]) Ppt =
&Fifo[0]; /* Wrap */<BR> if (Ppt == GETPT ){
<BR> END_CRITICAL(); /*
end critical section
*/<BR> return(0);} /*
Failed, fifo was full */<BR> else{
<BR> PUTPT=Ppt;<BR> END_CRITICAL(); /*
end critical section
*/<BR> return(-1); /*
Successful */ <BR> }<BR>}<BR>int GetFifo (char *datapt)
{unsigned char SaveSP;<BR> if (PUTPT== GETPT){
<BR> return(0);} /*
Empty if PUTPT=GETPT */<BR> else{
<BR> START_CRITICAL(); /* make
atomic, entering critical section
*/<BR> *datapt=*(GETPT++);<BR> if
(GETPT ==
&Fifo[FifoSize])<BR> GETPT
=
&Fifo[0];<BR> END_CRITICAL();
/* end critical section
*/<BR> return(-1);<BR> }<BR>}</CODE></P></DIR>
<ADDRESS><FONT face="Times New Roman,Times">Listing 7-3: Fifo queue implemented
with pointers</FONT></ADDRESS>
<P>The START_CRITICAL and END_CRITICAL macros are specific to ICC11/ICC12,
otherwise this example will operate using Hiware.</P>
<P><FONT face="Times New Roman,Times">Since these routines have read modify
write accesses to global variables the three functions (InitFifo, PutFifo,
GetFifo) are themselves not reentrant. Consequently interrupts are temporarily
disabled, to prevent one thread from reentering these Fifo functions. One
advantage of this pointer implementation is that if you have a single thread
that calls the GetFifo (e.g., the main program) and a single thread that calls
the PutFifo (e.g., the serial port receive interrupt handler), then this PutFifo
function can interrupt this GetFifo function without loss of data. So in this
particular situation, interrupts would not have to be disabled. It would also
operate properly if there were a single interrupt thread calling GetFifo (e.g.,
the serial port transmit interrupt handler) and a single thread calling PutFifo
(e.g., the main program.) On the other hand, if the situation is more general,
and multiple threads could call PutFifo or multiple threads could call GetFifo,
then the interrupts would have to be temporarily disabled as shown.</FONT></P>
<P><B><I><FONT face=Helvetica,Arial><A name=IO></A>I/O Port
Access</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">Even though the mechanism to access I/O
ports technically does not fit the definition of pointer, it is included in this
chapter because it involves addresses. The format used by both the Imagecraft
and Hiware compilers fits the following model. The following listing shows one
8-bit and two 16-bit 6811 I/O ports. The line TFLG1=0x08; generates an 8-bit I/O
write operation to the port at address 0x1023. The TCNT on the right hand side
of the assignment statement generates a 16-bit I/O read operation from the port
at address 0x100E. The TOC5 on the left hand side of the assignment statement
generates a 16-bit I/O write operation from the port at address 0x101E. The
TFLG1 inside the while loop generates repeated 8-bit I/O read operations until
bit 3 is set.</FONT></P>
<DIR>
<P><CODE>#define TFLG1 *(unsigned char volatile *)(0x1023)<BR>#define TCNT
*(unsigned short volatile *)(0x100E)<BR>#define </CODE><FONT face=Courier
size=2>TOC5 </FONT><CODE>*(unsigned short volatile *)(0x101E)<BR>void
wait(unsigned int delay){<BR> TFLG1=0x08; /* clear OC5F
*/<BR> TOC5=TCNT+delay; /* TCNT at end of wait
*/<BR> while((TFLG1&0x08)==0){}; /* wait for
OC5F*/<BR></CODE><FONT face=Courier size=2>}</FONT></P></DIR>
<P><I>Listing 7-4: Sample ICC11/Hiware Program that accesses I/O ports</I></P>
<P><FONT face="Times New Roman,Times">A similar 6812 program is shown
below.</FONT></P>
<DIR>
<P><CODE>#define TFLG1 *(unsigned char volatile *)(0x008E)<BR>#define TCNT
*(unsigned short volatile *)(0x0084)<BR>#define </CODE><FONT face=Courier
size=2>TC5 </FONT><CODE>*(unsigned short volatile *)(0x009A)<BR>void
wait(unsigned int delay){<BR> TFLG1=0x20; /* clear C5F
*/<BR> TC5=TCNT+delay; /* TCNT at end of wait
*/<BR> while((TFLG1&0x20)==0){}; /* wait for
C5F*/<BR></CODE><FONT face=Courier size=2>}</FONT></P></DIR>
<P><I>Listing 7-5: Sample ICC12/Hiware Program that accesses I/O ports</I></P>
<P><FONT face="Times New Roman,Times">It was mentioned earlier that the volatile
modifier will prevent the compiler from optimizing I/O programs. I.e., these
examples would not work if the compiler read TFLG1 once, the used the same data
over and over inside the while loop.</FONT></P>
<P><FONT face="Times New Roman,Times">To understand this syntax we break it into
parts. Starting on the right is the absolute address of the I/O port. For
example the 6811 TFLG1 register is at location 0x1023. The parentheses are
necessary because the definition might be used in an arithmetic calculation. For
example the following two lines are quite different:</FONT></P>
<P><CODE> TheTime=*(unsigned char volatile
*)(0x1023)+100;<BR> TheTime=*(unsigned char volatile
*)0x1023+100;</CODE></P>
<P><FONT face="Times New Roman,Times">In the second (incorrect) case the
addition 0x01023+100 is performed on the address, not the data. The next part of
the definition is a type casting. C allows you to change the type of an
expression. For example (unsigned char volatile *) specifies that 0x1023 is an
address that points at an 8-bit unsigned char. The * at the beginning of the
definition causes the data to be fetched from the I/O port if the expression
exists on the right-hand side of an assignment statement. The * also causes the
data to be stored at the I/O port if the expression in on the left-hand side of
the assignment statement. In this last way, I/O port accesses are indeed similar
to pointers. For example the above example could have be implemented
as:</FONT></P>
<DIR>
<P><CODE>unsigned char volatile *pTFLG1;<BR>unsigned short volatile
*pTCNT;<BR>unsigned short volatile *p</CODE><FONT face=Courier
size=2>TC5</FONT><CODE>;<BR>void wait(unsigned int
delay){<BR> pTFLG1=(unsigned char volatile
*)(0x008E);<BR> pTCNT=(unsigned short volatile
*)(0x0084);<BR> p</CODE><FONT face=Courier
size=2>TC5</FONT><CODE>=(unsigned short volatile
*)(0x009A);<BR> (*pTFLG1)=0x20;
<BR> (*pTC5)=(*pTCNT)+delay;
<BR> while(((*pTFLG1)&0x20)==0){}; <BR></CODE><FONT
face=Courier size=2>}</FONT></P></DIR>
<P><I>Listing 7-6: ICC12/Hiware Program that accesses I/O ports using
pointers</I></P>
<P><FONT face="Times New Roman,Times">This function first sets the three I/O
pointers then accesses the I/O ports indirectly through the pointers.</FONT></P>
<P> </P>
<P><FONT face="Times New Roman,Times">Go to <A
href="http://www.ece.utexas.edu/~valvano/embed/chap8/chap8.htm">Chapter 8 on
Arrays and Strings</A> Return to <A
href="http://www.ece.utexas.edu/~valvano/embed/toc1.htm">Table of Contents</A>
</FONT></P>
<P> </P></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -