From 47f0f0045c92d5b3b84962bb2f9c2c4b02d96379 Mon Sep 17 00:00:00 2001 From: Phil Hord Date: Fri, 28 Aug 2015 15:37:45 -0400 Subject: [PATCH] MOVEBUFFER_SIZE really does not have to be power of 2 A comment in dda_queue.h says that MOVEBUFFER_SIZE no longer needs to be a power of 2 in size. The comment is from a commit in 2011, but only queue_full seems to be modified to make this true. Other places in the code still assume that MOVEBUFFER_SIZE is always a power of 2, wrapping it with "& (MOVEBUFFER_SIZE-1)". Add a MB_NEXT(x) macro which can be used to definitively find the next slot in the queue without using any boolean math. Replace all the queue-position functions with new code that uses this MB_NEXT function instead. Also change the queue_full function to use this simpler method instead of the complicated multi-step confusion which it did. --- dda_queue.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/dda_queue.c b/dda_queue.c index 9dae2c5..3054905 100644 --- a/dda_queue.c +++ b/dda_queue.c @@ -35,14 +35,13 @@ uint8_t mb_tail = 0; /// The size does not need to be a power of 2 anymore! DDA BSS movebuffer[MOVEBUFFER_SIZE]; +/// Find the next DDA index after 'x', where 0 <= x < MOVEBUFFER_SIZE +#define MB_NEXT(x) ((x) < MOVEBUFFER_SIZE - 1 ? (x) + 1 : 0) + /// check if the queue is completely full uint8_t queue_full() { MEMORY_BARRIER(); - if (mb_tail > mb_head) { - return (mb_tail - mb_head - 1 == 0); - } else { - return (mb_tail + MOVEBUFFER_SIZE - mb_head - 1 == 0); - } + return MB_NEXT(mb_head) == mb_tail; } /// check if the queue is completely empty @@ -107,8 +106,7 @@ void enqueue_home(TARGET *t, uint8_t endstop_check, uint8_t endstop_stop_cond) { while (queue_full()) delay_us(100); - uint8_t h = mb_head + 1; - h &= (MOVEBUFFER_SIZE - 1); + uint8_t h = MB_NEXT(mb_head); DDA* new_movebuffer = &(movebuffer[h]); @@ -148,7 +146,7 @@ void enqueue_home(TARGET *t, uint8_t endstop_check, uint8_t endstop_stop_cond) { /// go to the next move. /// be aware that this is sometimes called from interrupt context, sometimes not. -/// Note that if it is called from outside an interrupt it must not/can not by +/// Note that if it is called from outside an interrupt it must not/can not /// be interrupted such that it can be re-entered from within an interrupt. /// The timer interrupt MUST be disabled on entry. This is ensured because /// the timer was disabled at the start of the ISR or else because the current @@ -157,8 +155,7 @@ void enqueue_home(TARGET *t, uint8_t endstop_check, uint8_t endstop_stop_cond) { void next_move() { while ((queue_empty() == 0) && (movebuffer[mb_tail].live == 0)) { // next item - uint8_t t = mb_tail + 1; - t &= (MOVEBUFFER_SIZE - 1); + uint8_t t = MB_NEXT(mb_tail); DDA* current_movebuffer = &movebuffer[t]; // Tail must be set before calling timer_set(), as timer_set() reenables // the timer interrupt, potentially exposing mb_tail to the timer