The LS7366 is a 32 bit counter with a direct interface for quadrature signals from incremental encoders. There is also an index channel for marker functions. The interface to the microcontroller is SPI mode 0 making it relatively easy to drive with a variety of common controllers. Decimus has one of these on each motor channel connected to the encoders on the back of the Faulhaber 2224 coreless motors. There is very little information about these chips available except the data sheet. This is how they are used on Decimus.Interface to the encoders is very easy as the phase inputs can be connected directly to the chip. A clock signal must be provided for the counter and I used the same 8MHz oscillator that drives the processor on Decimus. the clock will need to be less than 40MHz in a 5V system and must be greater than 4 times the maximum count frequency. Even at a speed of 5m/s Decimus will only be generating encoder pulses at about 140kHz so there is plenty of margin.The counter is very flexible and can be configured for x1, x2, x4 and non-quadrature counting and the counter register may be set to 8, 16, 24 or 32 bits in size. Selecting x1 decoding will give 512 counts per revolution of the motor shaft and 2048 counts per revolution of the wheel. For this application, the counter width will be set to 8 bits. This is the fastest to read back from the counter and has sufficient range for my needs. With a single byte counter, the maximum difference in counts that can be reliably detected between two reads is 127. Since each count on Decimus is 24mm * pi / 512 * 4 or about 0.04mm. The control loop runs at 1KHz so the maximum recordable speed would be 127 * 0.04mm / 1ms which is around 5m/s. Practically speaking, the mouse would almost never be able to reach such a speed in the maze and the top speed will be limited to no more than 4m/s by the control loop.Configuring the chip is a question of sending a number of values to internal registers over the SPI. Here is a code fragment for the mouse initialisation:
CNTR_LEFT_SEL = 0; // start a command SPI_putc(WR + MDR0); // write MDR0 SPI_putc(CLOCK_DIV_2 + FREE_RUN + CNT_MODE_X1); // free-running, x1 decoding CNTR_LEFT_SEL = 1; // end this command asm("nop");asm("nop");asm("nop"); // delay between commands CNTR_LEFT_SEL = 0; // start next command SPI_putc(WR + MDR1); // write MDR1 SPI_putc(COUNT_ENABLE + CNTR_WIDTH_1); // enabled, single-byte CNTR_LEFT_SEL = 1; // end command asm("nop");asm("nop");asm("nop"); // delay between commands CNTR_LEFT_SEL = 0; // start next command SPI_putc(CLR + CNTR); // clear the counter CNTR_LEFT_SEL = 1;
The only real ‘gotcha’ was not noticing that after each command the select line must be raised to complete the command then lowered again for the next command. There is a minimum time the line must be held high, hence the ‘NOP’ instructions. The setup and hold times for the select line are easily met by the overhead of the function call for the SPI_putc() function.Reading the counter is also quite straightforward. A command is sent to read the counter. This transfers the current counter value to the output register and the next write to the chip clocks out that register. You must perform as many reads as there are bytes. Remember that the data comes out MSB first so you can’t just read the low bytes and ignore the rest. Like all SPI systems, a byte has to be sent so that you can get a byte back as transfers occur simultaneously in both directions. So for example, if the counter were set up for a 16 bit width, the current value can be read with code like this:
CNTR_LEFT_SEL = 0; SPI_putc(RD + CNTR); // transfer CNTR to OTR and prepare to read temp1 = SPI_putc(0x00); // send a dummy byte to get the first byte back temp1 = (temp1 << 8); // we get the high byte first temp1 += SPI_putc(0x00); // another dummy byte gets the lower byte returned CNTR_LEFT_SEL = 1;
This is fairly quick. Reading both encoders in 16 bit mode takes just under 30us on Decimus with the SPI running a 4MHz clock.