-
Project Wrap-Up
10/01/2018 at 15:23 • 0 commentsSo... I wasn't ultimately able to get past my soldering issues so I wasn't able to get any of the boards working to the point where I could start writing and testing software. I think the problem was that I included a via connecting the ground pads of the uC and the CAN interface together, which was enough to push the solderability over the line of what I am capable of doing.
I was, however, able to get the basic requirements of the contest (gerbers, pictures of assembled project, and parts list) together in time.
This was sort of a practice run at something I've been thinking about since Toorcamp this year, which is a line of cheap, single-function CAN interface boards. I.e. something like this board plus various sensor and actuator interfaces. The boards will be bigger (1 x 2 inches) and all the components will be on one side. There's a nice low-end STM32 chip that has built-in CAN which I expect to use as the heart of that line of boards. I'll be opening a new Hackaday.io project to hold that. Here's my preliminary line-up:- DC brushed motor controller
- 9-axis IMU
- 4 ch 24 bit ADC with programmable gain amplifier & onboard temperature sensor
- SPI & I2C interface with proto area
- Stepper motor controller (probably a RAMPS carrier with feedback provisions)
- Servo output
- DAC output
- GPS
- High current DC switches
-
One step forward, one step back
09/26/2018 at 05:32 • 0 commentsMy day job has owned most of my headspace this month, so I've just gotten to the point where I have my three boards assembled and powered up. The good news is that none of them show any sign of shorts or any similar problems. The bad news is that not a single one responds to the programmer... and probing around makes it look like none of the reset lines got connected when I soldered down the processors. I don't think my hands are steady enough at this hour to fix it, so I will give it a swing tomorrow.
I did manage to get the CAN interface library ported to C and compiling, so I'm not quite out of the running yet. I'm not entirely confident of my ability to get beyond current control in the time I have left, but we will see. -
Oh goody...
09/06/2018 at 07:40 • 0 commentsIt appears that in order to get one of the existing MCP2515/25625 libraries to play nice with the ASF drivers in the project created by Atmel START, I need to port it over to plain C. This isn't completely horrible, since the one I picked mostly just use C++ for encapsulation and I'm not trying to run multiple chips. Still a pain in the neck to refactor, and I'm not entirely sure how to set up Atmel Studio to suck in the files in any way that does not involve just copying them in.
In better news, I think I have my configuration finished, and I think I found a way to use the event system to use Timer/Counter B to capture the time of each encoder pulse. That wraps up way too much hemming and hawing just in time for the boards to show up. One possible wrinkle, however, is that the pulses off the edge detector as built are very short as it uses the main clock to drive the clock input of the flip-flop. Therefore, I am not 100% sure it will capture all pulses and I won't have the opportunity to find out until I have the boards in hand and assembled. -
New boards ordered
09/02/2018 at 21:08 • 0 commentsOk, got the new boards ordered, expect them by Friday. Pictures of the new design are up and I've pushed it to Github. I decided to take the opportunity to fix my encoder issues with an external edge detector circuit.
-
Never too smart to make a dumb mistake...
09/01/2018 at 17:19 • 0 commentsI got the boards back from OSHPark's swift service... and discovered that I had made a dumb mistake. I used someone else's QFN-20 footprint (because lazy/in a hurry/etc) and discovered that it is entirely the wrong size. So this spin of boards is junk... luckily it's only $10 (one of the advantages of the limits of this contest) so I'm mostly just out the time. I also found that I'd forgotten to order the resonators, so there's that too. I guess next weekend is going to be a bit of a sprint; luckily OSHPark will be able to get me boards in time.
However, this gives me the opportunity to revisit an earlier issue, which is adding external logic to give me a nice pulse on each encoder transition. Turns out I can find places for the parts, and since I need to order both boards and parts already, it's an easy decision to make. New pictures and board files will go up tonight or tomorrow.
-
More (en)code(r) fun
08/29/2018 at 06:25 • 0 commentsMy components have arrived and my boards have shipped... so I'm continuing to bang my head against the encoder problem in the meantime.
As an aside, this process of poking around has been greatly helped by the configuration tools at start.atmel.com, which give you a way to configure all the libraries and peripherals you need for your AVR or Atmel ARM project and export the setup code as an Atmel Studio project ready to go. Since the '816 is significantly different than earlier ATTinys, this has been a huge help in getting me up and running and futzing around with peripherals.
I can certainly capture every other transition easily enough -- configure LUT0 as an XOR on the two phases and feed it into one of the event lines and drive the capture input of one of the timers from there. But I could do twice as well so I'm spinning my wheels a bit.
If I feed the output of LUT0 and the output of the optional D flip-flop into LUT1 and configure it as another XOR, I should get a one clock cycle pulse on the output of LUT1 -- enough to clock the flip-flop and trip the counter. I tried doing this with the outputs of LUT1 and the DFF fed out to two I/O pins, but I did not see any evidence of output using my logic analyzer.
My next trick is to hook up an interrupt to the counter capture so I can toggle a pin every time the counter capture fires... and this isn't firing at all. That troubles me more than almost anything else because if I can't get that hookup to work it means that I'm SOL on getting any help from the CCL on making the encoder work better than I get from just hanging pin change interrupts on the two input lines.The encoder I've been using for testing (a super cheap thing designed for panel controls) has some mechanical bounce to it, which means I have a way to judge the minimum time to sample a single edge.
The first time I tried this, the results were awful -- 3-4 us of delay from a transition to the pin toggle I attached to the interrupt. Then I realized I'd left the clock prescaler turned on. Once I turned it off, I'm clocking a very consistent 720 ns from incoming edge to toggle. Since I anticipate a minimum time between transitions of ~33 us, this is good enough for a passable velocity controller.
So enough about that problem and on to the next one. -
Components ordered, more encoder musings
08/24/2018 at 06:47 • 0 commentsI ordered the components and they should be here early next week.
I'm expecting an ATTiny817 dev board tomorrow, so I can start messing around with the CCL and the encoders. I am currently not seeing a way to get the signal I want (rising edges on every transition) without at least one extra component. I think I might be able to make it work with a single off-board gated D flip-flop (DFF) and both LUTs configured as XORs based on this dual edge detector circuit from Cypress (at the bottom). LUT0 would XOR the two phases together, generating a single signal with an edge for each transition, and pass it out an I/O pin to the offboard DFF. The output of that would pass back to LUT1 through an I/O pin, where it would be XORed with the output of LUT0, generating a rising edge on every transition, perfect for feeding to one of the internal timer/counters.
That feels like admitting defeat. Also, I'd have to do a third board spin (!!) before I assembled the first one, which is not really the way I want to roll.So... I think I'm going to do this the dumb way. I'll set TCB as the timer for my main loop and set up TCA to track the cycles since the start. I can then make both of the phase inputs interrupts, and use the current value of TCA to track how long its been since the last transition. We'll see how well this works in practice.
-
Second round of boards & encoder fun
08/22/2018 at 15:47 • 0 commentsTurns out I made a mistake and never ordered the first round of boards. It's an irrelevant oops, since I would have just had to scrap them on arrival.
This morning I ordered new boards with the super-swift service from OSHPark. I thought about going with the 2 oz copper instead, but since the high current traces on this board are so broad and short, I can go without the heavier copper and I want my boards stat. I haven't bothered uploading new pictures yet, because almost all the changes are with traces and aren't particularly visible on board level images.
There is one change of note, and that's that I went to a three pin programming header. The ATTiny816 is designed to be programmed through the reset line alone, not through the SPI port like previous generations of AVRs. This lets me switch to an 0.1" pitch programming header, which means less futzing with wires and more just plugging the thing into my programmer.
I also ordered an ATTin817 Xplained Mini and a couple of encoders for delivery Friday, because I am not having a great time figuring out how to make the encoder logic work the way I want it to.
A quadrature encoder has four state transitions per pulse. That means that you can, in principle, quadruple the resolution of a given encoder by taking measurements at each transition -- a 48 pulse per revolution encoder now counts 192 times per revolution with just a bit of software. However, this is a bit more difficult in practice.
The most straightforward way to approach this is to connect each phase of the encoder to a separate interrupt pin, set them to transition on rising and falling edges, and use a timer to measure the times of transition. This is fine as far as it goes, but is subject to jitter if there are any other interrupts in the system, such as a main loop timing interrupt, and depending on how interrupts are scheduled, may result in some steps being dropped entirely. That jitter doesn't matter much if you are controlling only position with no velocity control or differential terms in the control loop. However, we will be controlling velocity, and the noise in the velocity measurement caused by jitter is to be avoided. So we're going to take a somewhat harder road.There are two subsystems/peripherals that make it possible to do something better with the '816. The Timer/Counter B has a frequency measurement mode that copies out the counter value and fires an interrupt on the rising edge of a single input. That would not be enough by itself without some off-chip glue logic, but the '816 has something called Configurable Custom Logic (CCL) on the chip.
The CCL has two configurable three input lookup tables (LUTs). They can be configured to any of the 256 possible three input logic truth tables. Two of the inputs of each LUT can come from input pins -- if you remember from the last update, phases A & B of the encoder are wired to the inputs of LUT0. Each LUT has an optional filter and an optional rising edge detector. The outputs of the two LUTs may optionally be connected to a sequential logic element -- either a JK flipflop, a D flipflop, a D latch, or an RS latch. Finally, the output of the sequential logic element can be fed back to either LUT, and each LUT can also take the output of the other LUT as an input.
I'm reasonably certain that somewhere in all this is a way to create what I really need, which is an internal signal that provides a rising edge on each transition of the two input pins. Tonight I will draw it out and post further. -
Rerouting all the signals
08/15/2018 at 04:55 • 0 commentsSo, it appears that I stuffed up the routing of the signals into the ATTiny816 on my initial design... time to re-do it, right this time. Here's a quick overview of what I need to connect
- Clock input from the CAN interface
- Reset/programming line
- SPI (CS, MISO, MOSI, and SCLK) to the CAN interface
- Two complementary PWM outputs to the motor
- A, B, and Z lines from the encoder
- One analog input from the motor
- Interrupt line from the CAN interface
- Reset line to CAN interface
- One enable line to the motor
Forced Allocations
Three of these can only go to particular pins.
- The reset/programming line is PA0 (pin 19). One of the advantages of the ATTiny 816 is that it is designed to be programmed and debugged via the reset line alone; this makes the programming header much more compact, since the rest of the SPI interface does not need to be connected as it is with earlier AVR parts.
- The clock input must go to PA3 (pin 2)
- There are two options for SPI on this part, but the default option (PA1-4) overlaps the clock input, so we must use the other option, which is PC0-3, or pins 15-18.
Timer/Counter Allocations
There are three functions in this design that require timer/counter services (timer interrupts, PWM, and encoder input), and only three timer/counters on the chip. These timer/counters are connected to a fairly limited set of pins.
Allocating the PWM is simple, because Timer/Counter D has specific functions for generating complementary PWM signals with configurable deadband and other features particularly useful for controlling motors. It has four output pins -- PA4, PA5, PC0, and PC1. Since PC0 and PC1 are already allocated to the SPI, PA4 & PA5 are allocated to PWM.
The encoder is a bit trickier, because I want to count both the rising and falling edges of phases A & B of the encoder in order to quadruple the number of counts per revolution. The timer/counter peripherals are only able to count on a single channel. Luckily, the ATTiny816 provides configurable custom logic (CCL) to enable me to get around this limitation. The XOR of phase A & B will transition on every edge, and the CCL provides the ability to do this. Unfortunately, there are only two available CCL input pins still available, PA1 & PA2, so they are allocated to encoder phases A & B. Since only Timer/Counter B offers a frequency measurement mode, the encoder is allocated to Timer/Counter B.
This leaves Timer/Counter A to generate the timer interrupts that drive the control loops
Other Allocations
The analog input from the motor must go into one of the analog pins, which are PA0-7, PB0-1, and PB4-5 on the '816. In order to limit the amount of re-routing, we'll allocate PA6 to motor current feedback.
Phase Z of the encoder fires once per revolution to provide a more absolute position signal. One of the nice features of the '816 is that any pin can be used as an interrupt, so we'll leave it where it is (PB3)
The motor enable line can go anywhere, so we'll move it the shortest distance available, to PA7.
The CAN reset and interrupt lines can go anywhere, so we'll allocate them to PB0 and PB1.
All of these allocations are subject to change for routing convenience. Here's a handy table:
Pin Name Pin (QFN) Function PA0 19 Reset/UDPI PA1 20 Encoder Phase A PA2 1 Encoder Phase 2 PA3 2 Clock Input PA4 5 Motor PWM 1 PA5 6 Motor PWM 2 PA6 7 Motor Current Sense PA7 8 Motor Enable PB0 14 CAN reset PB1 13 CAN interrupt PB3 11 Encoder Phase Z PC0 15 SPI SCK PC1 16 SPI MISO PC2 17 SPI MOSI PC3 18 CAN CS -
Uh-oh
08/14/2018 at 15:03 • 0 commentsWhelp... turns out that I stuffed up the pinout and need to re-route and re-spin so that the Timer/Counter channels and so on are hooked up in the correct places. This thing was a pain to route in the first place -- so much fun to do it again!
Since this project uses three different timer/counter peripheral functions (PWM, timer interrupts, and encoder input), I need to be pretty careful about how I use the peripherals.