I’ve been spending some time in the last weeks working on porting Sprinter over to my new SAM3U-based 4pi electronics. I’ve extracted several useful elements into libraries (sort of) so they can be used for other projects too.

ADC - samadc.c

The 12 bit ADC built into the SAM3U has 8 channels. 4 of them (channels 5,3,1, and 2) are wired to the thermistor voltage dividers. Channels 4, 6 and 7 are connected to the X, Y, and Z max endstop pins, but can be used as ADC channels as well. They are disabled by default. Channel 0 is not available on 4pi.

To use the ADC, its initialization function is called with an argument that specifies whether the ADC is to take continuous readings or only make a measurement when one is requested:

void initadc(int autos);

Where autos is 0 for manual sampling and >0 for continuous sampling.

unsigned int adc_read(unsigned char channel);

Where channel is a number from 1 to 7. The value returned is in millivolts. adc_read will never block. It will always return the last value sampled on any of the enabled channels. If you are running in continuous mode, you can rely on this being a very recent value. If not running in continuous mode, you have to call a function to initiate a read:

void adc_sample();

This will make a measurement on all the enabled channels. In Sprinter, I’ve set it up to make a measurement 100 times per second.

Motor options - motoropts.c

The 5 motor drivers on the 4pi all have adjustable current levels and microstepping settings. This file abstracts these settings and lets you control the stepper drivers.

Before you use the motor drivers, they must be initialized. Use the

void motor_setup();

function to do this. This sets each motor to 1/16th microstepping, at half current. All motors are disabled on startup.

To adjust the microstepping or current settings of an axis, use

void motor_setopts(unsigned char axis, unsigned char ustepbits, unsigned char current);

axis is a number from 0 to 4, corresponding respectively to X, Y, Z, E0 and E0 drivers. The AD5206 digital potentiometer has six channels, and the three pins of the remaining channel are brought out to solder pads on the board. You can use axis number 6 to adjust its current. ustepbits are the microstepping settings on the stepper drivers. The values are 0 for full step, 1 for half step, 2 for 1/4 step and 3 for 1/16 step. You can put in 4 here to leave the microstepping unchanged and adjust only current. current is an integer from 0 to 255 that adjusts the current limit of the motor. 255 is full power, 0 is off.

There is a function to enable or disable an axis as well:

void motor_enaxis(unsigned char axis, unsigned char en);

Where axis is as above and en is 0 for disable and >0 for enable. A similar function exists for setting the direction:

void motor_setdir(unsigned char axis, unsigned char dir);

Finally, to step an axis, use:

void motor_step(unsigned char axis);
void motor_unstep();

motor_step will set the step pin for a given axis high, motor_unstep will set all axes low. These functions will always be inlined.

Heater/FET control - heaters.c

The heater and FET control is fairly simple. You initialize the FETs with the


function. All heaters are off on startup. After that, you can switch each channel with the

heater_switch(unsigned char heater, unsigned char en);

function. If en==0, the FET will be switched off. If en>0, it will be switched on. The FET IDs are:

0 - Bed heater
1 - Extruder 0 (E0)
2 - Extruder 1 (E1)
3 - AUX0
4 - AUX1

Systick timer

The SAM3U has an ARM Cortex-M3 processor. That processor has a systick timer that counts down from a given 24bit value to zero on either every clock tick or every eighth clock tick of the master clock. It can generate an interrupt whenever the counter reaches zero, and gets automatically reset to the initial value. This is a nice way to get a periodic timer “for free” as it leaves the other three timers on the chip free for more sophisticated stuff. I use the systick timer to generate an interrupt every millisecond. This currently drives the temperature measurement as well as updating a clock that a number of functions in Sprinter use.

USB-Serial - serial.c

The SAM3U has a native high speed USB controller running at 480MHz. This required some creative routing to attach to the USB port as traces carrying signals at that speed need to be precisely length-matched:

Length-matched traces

I implemented a virtual serial port running over the USB link, that shows up as an ACM device. Most of the work is done by libs Atmel helpfully provides (with a BSD license too!) in their at91lib. Here are the functions I wrote:

void samserial_init();
void samserial_print(const char* c);
void samserial_setcallback(void (*c)(unsigned char));

samserial_init initializes the serial port with a default baudrate of 115200bps (I’ll make that configurable later). samserial_print attempts to write a string to the virtual serial port. samserial_setcallback takes a function pointer and calls the function whenever a new character is received on the serial port. The Sprinter flow control code and checksum calculator gets attached to this callback.

blog comments powered by Disqus


29 August 2012