Skip to content

Instantly share code, notes, and snippets.

@djmips
Last active June 13, 2020 17:53
Show Gist options
  • Save djmips/3597baf53c74dd1c71bc0e9445dd7466 to your computer and use it in GitHub Desktop.
Save djmips/3597baf53c74dd1c71bc0e9445dd7466 to your computer and use it in GitHub Desktop.
Line Draw into SAM3x8e DMA buffer (Arduino DUE)
// Assume there is a currX and currY global state which is the current x,y position
// Assume that currBuffer points to a valid properly sized buffer in RAM for DMA
//
// Buffer size can be calculated as n * 4 bytes where n is max(xdelta, ydelta)
// where xdelta and ydelta are the extents of the line to be drawn
//
// xd and yd is the destination point
//
// The output DACs are 12 bit but for speed this outputs in steps of 4 to cut the point generation by 4 times
// Effective resolution is 1024 points in X and Y
//
// The routine uses a SWAR (SIMD within a register) technique of operating on two 16 bit values within a 32 bit register
//
// So in summary the words are 16 bit and only the low 12 bits are used for the DAC. And then I'm only stepping in 10 bit resolution
// The extra OR with 0x10000000 is a hardware flag to use the other DAC
// y is in the low word and x is in the high word
#define DAC_PACK_COORD(_x, _y) (((0x0FFF & (_y)) << 2) | ((0x0FFF & (_x)) << 18) | 0x10000000)
void line(uint16_t xd, uint16_t yd) {
uint16_t x1 = currX;
uint16_t y1 = currY;
uint16_t x2 = xd;
uint16_t y2 = yd;
// updated the new currX and currY to be the end position
currX = x2;
currY = y2;
uint16_t dx; // abs(deltax)
uint16_t dy; // abs(deltay)
uint16_t hx; // counter used when moving predominatnly in the x direction
uint16_t hy; // counter used when moving predominantly in the y direction
uint16_t ddx; // accumulator to decide when to move in the
uint16_t ddy; // accumulator
// packs both x and y into a 32 bit word suitable for DMA to DAC on Arduino DUE
uint32_t coord = DAC_PACK_COORD(x1,y1);
if (x1 > x2) {
dx = x1-x2;
if (y1 > y2) {
dy = y1-y2;
if (dy > dx) {
hy = dy;
ddy = dy;
while(hy)
{
ddy = ddy - dx;
if (ddy < 0) {
coord = coord - (1 << 18); // Occasionally stepping by 1 in X (16 to shift to upper word and 2 more for increments of 4)
ddy = ddy + dy;
}
currBuffer[bufferCounter++] = coord;
coord = coord - (1<<2); // Always stepping by 1 in Y (increments of 4 because of 10 bit stepping)
hy = hy - 1;
}
} else {
hx = dx;
ddx = dx;
while(hx)
{
ddx = ddx - dy;
if (ddx < 0) {
coord = coord - (1<<2);
ddx = ddx + dx;
}
currBuffer[bufferCounter++] = coord;
coord = coord - (1 << 18);
hx = hx - 1;
}
}
} else {
dy = y2-y1;
if (dy > dx) {
hy = dy;
ddy = dy;
while(hy)
{
ddy = ddy - dx;
if (ddy < 0) {
coord = coord - (1<<18);
ddy = ddy + dy;
}
currBuffer[bufferCounter++] = coord;
coord = coord + (1<<2);
hy = hy - 1;
}
} else {
hx = dx;
ddx = dx;
while(hx)
{
ddx = ddx - dy;
if (ddx < 0) {
coord = coord + (1<<2);
ddx = ddx + dx;
}
currBuffer[bufferCounter++] = coord;
coord = coord - (1<<18);
hx = hx - 1;
}
}
}
} else {
dx = x2-x1;
if (y1 > y2) {
dy = y1-y2;
if (dy > dx) {
hy = dy;
ddy = dy;
while(hy)
{
ddy = ddy - dx;
if (ddy < 0) {
coord = coord + (1<<18);
ddy = ddy + dy;
}
currBuffer[bufferCounter++] = coord;
coord = coord - (1<<2);
hy = hy - 1;
}
} else {
hx = dx;
ddx = dx;
while(hx)
{
ddx = ddx - dy;
if (ddx < 0) {
coord = coord - (1<<2);
ddx = ddx + dx;
}
currBuffer[bufferCounter++] = coord;
coord = coord + (1<<18);
hx = hx - 1;
}
}
} else {
dy = y2-y1;
if (dy > dx) {
hy = dy;
ddy = dy;
while(hy)
{
ddy = ddy - dx;
if (ddy < 0) {
coord = coord + (1<<18);
ddy = ddy + dy;
}
currBuffer[bufferCounter++] = coord;
coord = coord + (1<<2);
hy = hy - 1;
}
} else {
hx = dx;
ddx = dx;
while(hx)
{
ddx = ddx - dy;
if (ddx < 0) {
coord = coord + (1<<2);
ddx = ddx + dx;
}
currBuffer[bufferCounter++] = coord;
coord = coord + (1<<18);
hx = hx - 1;
}
}
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment