Prusa3d Marlin fork
speed_lookuptable.h
1 #ifndef SPEED_LOOKUPTABLE_H
2 #define SPEED_LOOKUPTABLE_H
3 
4 #include "Marlin.h"
5 
6 extern const uint16_t speed_lookuptable_fast[256][2] PROGMEM;
7 extern const uint16_t speed_lookuptable_slow[256][2] PROGMEM;
8 
9 #ifndef _NO_ASM
10 
11 // return ((x * y) >> 8) with rounding when shifting right
12 FORCE_INLINE uint16_t MUL8x16R8(uint8_t x, uint16_t y) {
13  uint16_t out;
14  __asm__ (
15  // %0 out
16  // %1 x
17  // %2 y
18  // uint8_t: %An or %n
19  // uint16_t: %Bn %An
20  // __uint24: %Cn %Bn %An
21  // uint32_t: %Dn %Cn %Bn %An
22  //
23  //
24  // B2 A2 *
25  // A1
26  //---------
27  // B0 A0 RR
28  "mul %B2, %A1" "\n\t"
29  "movw %0, r0" "\n\t"
30  "mul %A2, %A1" "\n\t"
31  "lsl r0" "\n\t" //push MSB to carry for rounding
32  "adc %A0, r1" "\n\t" //add with carry (for rounding)
33  "clr r1" "\n\t" //make r1 __zero_reg__ again
34  "adc %B0, r1" "\n\t" //propagate carry of addition (add 0 with carry)
35  : "=&r" (out)
36  : "r" (x), "r" (y)
37  : "r0", "r1" //clobbers: Technically these are either scratch registers or always 0 registers, but I'm making sure the compiler knows just in case.
38  );
39  return out;
40 }
41 
42 // return ((x * y) >> 24) with rounding when shifting right
43 FORCE_INLINE uint16_t MUL24x24R24(__uint24 x, __uint24 y) {
44  uint16_t out;
45  __asm__ (
46  // %0 out
47  // %1 x
48  // %2 y
49  // uint8_t: %An or %n
50  // uint16_t: %Bn %An
51  // __uint24: %Cn %Bn %An
52  // uint32_t: %Dn %Cn %Bn %An
53  //
54  //
55  // C2 B2 A2 *
56  // C1 B1 A1
57  //------------------
58  // -- B0 A0 RR RR RR
59  "clr r26 \n\t"
60  "mul %A1, %B2 \n\t"
61  "mov r27, r1 \n\t"
62  "mul %B1, %C2 \n\t"
63  "movw %A0, r0 \n\t"
64  "mul %C1, %C2 \n\t"
65  "add %B0, r0 \n\t"
66  "mul %C1, %B2 \n\t"
67  "add %A0, r0 \n\t"
68  "adc %B0, r1 \n\t"
69  "mul %A1, %C2 \n\t"
70  "add r27, r0 \n\t"
71  "adc %A0, r1 \n\t"
72  "adc %B0, r26 \n\t"
73  "mul %B1, %B2 \n\t"
74  "add r27, r0 \n\t"
75  "adc %A0, r1 \n\t"
76  "adc %B0, r26 \n\t"
77  "mul %C1, %A2 \n\t"
78  "add r27, r0 \n\t"
79  "adc %A0, r1 \n\t"
80  "adc %B0, r26 \n\t"
81  "mul %B1, %A2 \n\t"
82  "add r27, r1 \n\t"
83  "adc %A0, r26 \n\t"
84  "adc %B0, r26 \n\t"
85  "lsl r27 \n\t"
86  "adc %A0, r26 \n\t"
87  "adc %B0, r26 \n\t"
88  "clr r1 \n\t"
89  : "=&r" (out)
90  : "r" (x), "r" (y)
91  : "r0", "r1", "r26" , "r27" //clobbers: Technically these are either scratch registers or always 0 registers, but I'm making sure the compiler knows just in case. R26 is __zero_reg__, R27 is a temporary register.
92  );
93  return out;
94 }
95 
96 #else //_NO_ASM
97 
98 FORCE_INLINE uint16_t MUL8x16R8(uint8_t charIn1, uint16_t intIn2)
99 {
100  return ((uint32_t)charIn1 * (uint32_t)intIn2) >> 8;
101 }
102 
103 FORCE_INLINE uint16_t MUL24x24R24(uint32_t longIn1, uint32_t longIn2)
104 {
105  return ((uint64_t)longIn1 * (uint64_t)longIn2) >> 24;
106 }
107 
108 #endif //_NO_ASM
109 
110 
111 FORCE_INLINE unsigned short calc_timer(uint16_t step_rate, uint8_t& step_loops) {
112  uint16_t timer;
113  if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY;
114 
115  if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times
116  step_rate = (step_rate >> 2)&0x3fff;
117  step_loops = 4;
118  }
119  else if(step_rate > 10000) { // If steprate > 10kHz >> step 2 times
120  step_rate = (step_rate >> 1)&0x7fff;
121  step_loops = 2;
122  }
123  else {
124  step_loops = 1;
125  }
126 
127  if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000);
128  step_rate -= (F_CPU/500000); // Correct for minimal speed
129  if(step_rate >= (8*256)){ // higher step rate
130  unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0];
131  unsigned char tmp_step_rate = (step_rate & 0x00ff);
132  uint16_t gain = (uint16_t)pgm_read_word_near(table_address+2);
133  timer = (unsigned short)pgm_read_word_near(table_address) - MUL8x16R8(tmp_step_rate, gain);
134  }
135  else { // lower step rates
136  unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0];
137  table_address += ((step_rate)>>1) & 0xfffc;
138  timer = (unsigned short)pgm_read_word_near(table_address);
139  timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3);
140  }
141  if(timer < 100) { timer = 100; }//(20kHz this should never happen)////MSG_STEPPER_TOO_HIGH c=0 r=0
142  return timer;
143 }
144 
145 #endif