4. Servicios
4.8 Otras acciones de apoyo al aprendizaje, la
The following program can be used to setup and read the 4-byte counter register from an LS7366R 32-bit quadrature counter. This is a device used for counting ticks on an encoder (see chapter 9). It is somewhat longer than the USART example as both the SPI peripheral on the ATmega644p must be configured to the requirements of the LS7366R as well as the LS7366R needing configuration. Once they are both configured and started, the program waits for one second and then reads the current count. This operation requires transmitting five bytes. The first byte is the actual command, telling the LS7366R what register is being read. The following four transmitted bytes are all ignored by the LS7366R as it is transmitting the counter value. This transmitted data is read from the same register as the transmitted data was written to. This program saves the incoming data byte by byte into an array of chars.
Determining commands for encoder counter
Before programming the microcontroller, the commands for the encoder counter must be determined. This includes the command to write to registers, the settings for the registers, and the command to read the counter itself. Figure 7.3 is an excerpt from the data sheet which explains how to form commands to be transmitted to the encoder counter.
The section at the top of figure 7.3 explains the instruction register on the encoder counter, and has a bit by bit description of each command. In this
Figure 7.3: How to form commands for the LS7366R Quadrature Encoder Counter. [17]
example the first required command is to write to the MDR0 (Mode Register 0) register. This register is the first of two controlling how the encoder counter operates. To write to this register requires the write command (B7:6 = 10) and the MDR0 register (B5:3 = 001) as seen to the right of the IR register description. For any command B2:0 can be anything. Here these bits will be 0. The com- mand required to write to MDR0 is therefore (bit 7 first) 0b10001000. According to the table in the datasheet extract the write command can be followed by 1-4 bytes of data. In this case, there is only one additional byte: the value to be stored in the MDR0 register, which will be determined shortly. The other two commands required by this program can be determined in the same way, which are the commands to write to the MDR1 register (0b10010000), and to read the CNTR register (0b01100000). The MDR1 register is the second mode register and requires again only a single byte of data. The CNTR register is the counter regis- ter. When reading from CNTR, that register is not actually what is transmitted. As is stated in the table in the excerpt, attempting to read CNTR actually copies the count into the OTR and transmits that. This copy prevents the counting and
transmitting operations from interfering with each other.
With the commands determined, the next step is to determine the data bytes to be written to MDR0 and MDR1. Figure 7.4 contains an excerpt from the datasheet specifying what the various settings for these two registers are.
Figure 7.4: Bit field descriptions for MDR0 and MDR1. [17] MDR0
B1:0: This controls how the counter handles the quadrature counts. In this example the highest precision will be used, which is the x4 count mode.
B3:2: This bit field modifies or limits what is counted. Here the free- running mode will be used, which causes every tick to be counted. In the event of overflowing the counter it will continue counting and set a carry bit in another register.
B5:4: These bits control the operation of an external pin called the index. In this case the pin is unused, so left disabled.
B6: As the index pin is not being used here, this bit doesn’t matter so is left as 0.
B7: This relates to a frequency crystal external to the encoder counter. As such it is left as 0 in this example. See the data sheet for further information.
With this information, the data byte to be written to this register is 0b00000011. MDR1
B1:0 This byte field controls how many bytes wide the counter is. This example uses a 4-byte counter.
B2 This enables counting. It must be set to 1 before any encoder ticks will be counted.
B3 Unused, so left as 0.
B7:4 These bits enable external pins to be used as flags for various con- ditions. These pins, if connected to the microcontroller, can trigger inter- rupts when certain conditions are met on the encoder counter. These are all disabled in this example.
The only bit in this register that needs to be set is the counter enable, so the byte to be written to this register is 0b00000100. At this point all the information required to create the program is gathered. Below is the code for this example. Example code # i n c l u d e < avr / io . h > # i n c l u d e < u t i l / d e l a y . h > # i n c l u d e " ../ l i b r a r i e s / r e g _ s t r u c t s . h " /* * * \ def SS S l a v e S e l e c t pin */ # d e f i n e SS P O R T B b i t s . _P4 /* * * \ f u n c S P I _ i n i t ()
* \ b r i e f i n i t i a l i z e s SPI for use w i t h L S 7 3 6 6 R */ v o i d S P I _ i n i t () { S P I D D R b i t s . _ M O S I = 1; S P I D D R b i t s . _ M I S O = 1; D D R B b i t s . _P4 = 1; S P C R b i t s . _ D O R D = 0; // MSB f i r s t
S P C R b i t s . _ M S T R = 1; // M a s t e r m o d e S P C R b i t s . _ C P O L = 0; // c l o c k low w h e n i d l e S P C R b i t s . _ C P H A = 0; // s a m p l e on l e a d i n g e d g e S P C R b i t s . _ S P R = 0; // 250 ns p u l s e S P S R b i t s . _w = 0; // f l a g s and d o u b l e s p e e d bit S P C R b i t s . _ S P E = 1; // e n a b l e SPI } /* * * \ f u n c S P I _ x m i t * \ p a r a m d a t a b y t e to x m i t * \ r e t u r n r e c e i v e d b y t e * \ b r i e f t r a n s m i t s d a t a and r e t u r n s r e c e i v e d d a t a */ c h a r S P I _ x m i t ( c h a r d a t a ) { S P D R b i t s . _w = d a t a ; w h i l e (! S P S R b i t s . _ S P I F ) {} // w a i t t i l l tx d o n e r e t u r n S P D R b i t s . _w ; // r e t u r n rx d a t a } /* * * \ f u n c q u a d _ c o u n t _ i n i t * \ b r i e f i n i t i a l i z e s L S 7 3 6 6 R q u a d r a t u r e c o u n t e r */ v o i d q u a d _ c o u n t _ i n i t () { SS = 1; // set s l a v e s e l e c t // M D R 0 : 0 b00 00 00 11: c l o c k /1 , async , i n d e x // d i s a b l e d , free - r u n n i n g c o u n t // 4 c o u n t s per q u a d c y c l e S P I _ x m i t (0 b 1 0 0 0 1 0 0 0 ); S P I _ x m i t (0 b 0 0 0 0 0 0 1 1 ); // M D R 1 : 0 b 0 0 0 0 x 0 0 0 : no flags , c o u n t i n g enabled , // 4 - b y t e c o u n t e r S P I _ x m i t (0 b 1 0 0 1 0 0 0 0 ); S P I _ x m i t (0 b 0 0 0 0 0 1 0 0 ); SS = 0; // c l e a r s l a v e s e l e c t } int m a i n ( v o i d ) { S P I _ i n i t (); q u a d _ c o u n t _ i n i t (); _ d e l a y _ m s ( 1 0 0 0 ) ; c h a r d a t a [ 4 ] ; int i = 0; SS = 1; // set s l a v e s e l e c t // l o a d C N T R to OTR t h e n r e a d OTR : 0 b01 100 xxx S P I _ x m i t (0 b 0 1 1 0 0 0 0 0 ); for ( i =0; i <4; i + + ) { d a t a [ i ] = S P I _ x m i t ( 0 ) ; // r e a d 4 b y t e s } SS = 0; // c l e a r s l a v e s e l e c t
// 32 bit c o u n t of e n c o d e r t i c k s now s t o r e d in // 4 b y t e s of d a t a a r r a y
r e t u r n 0; }
Example timing
In order to better understand what is happening during SPI communication, Figure 7.5 displays the states of all four SPI lines during a read operation of the CNTR register of the LS7366R Quadrature Counter. In the figure the CNTR register is setup to be 16 bits rather than the 32 used above. The sections on the MISO line marked tri-state are periods that the LS7366R is not actively controlling the line, even though the microcontroller may be sampling it. The sampled data for these times is garbage and is never read by the code. The section marked ”Random Data” is a period that the microcontroller must be transmitting something to cause the clock to oscillate, but the LS7366R ignores the MOSI line during this time.
Figure 7.5: States of all four SPI lines during operation to read 16 bit CNTR register from LS7366R Quadrature Counter.