Advertisement
DenseBrainMatrix

Untitled

Apr 25th, 2022
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.00 KB | None | 0 0
  1. #include <stdint.h>
  2. #include <stddef.h>
  3. #include "pru_uart.h"
  4. #include "pru_ecap.h"
  5. #include "sys_gpio.h"
  6.  
  7. // define PWM inputs for motor controll
  8. #define EPWM1A ( *(uint16_t volatile *)0x48302212 )
  9. #define EPWM1B ( *(uint16_t volatile *)0x48302214 )
  10.  
  11. // encoder position in other PRU core's memory
  12. #define position_var ((uint32_t const volatile *)0x00002000)
  13.  
  14. struct Message {
  15. uint32_t id;
  16. uint32_t timestamp;
  17. uint32_t position;
  18. int32_t control_signal;
  19. int16_t force;
  20. int16_t motor_effort;
  21. };
  22.  
  23. // layout of shared ddr3 memory (filled in by loader)
  24. struct DDRLayout {
  25. Message volatile *msgbuf;
  26. uint16_t num_msgs;
  27. uint16_t msg_size;
  28. };
  29.  
  30. struct SharedVars {
  31. // set by pru before halting
  32. char const *abort_file;
  33. int abort_line;
  34. // read-pointer updated by python
  35. uint16_t ridx;
  36. uint16_t signal[1000];
  37. };
  38.  
  39. far struct DDRLayout ddr __attribute__((location(0x10000))) = {};
  40. far struct SharedVars volatile shmem __attribute__((location(0x10100))) = {};
  41.  
  42. static inline uint32_t timestamp_cycles()
  43. {
  44. return CT_ECAP.TSCTR;
  45. }
  46.  
  47. // for easier debugging, record where in the source code we halted
  48. __attribute__((noreturn))
  49. void abort_at( char const *file, int line )
  50. {
  51. shmem.abort_file = file;
  52. shmem.abort_line = line;
  53. for(;;) __halt();
  54. }
  55.  
  56. static inline void assert_at( bool cond, char const *file, int line )
  57. {
  58. if( ! cond )
  59. abort_at( file, line );
  60. }
  61.  
  62. #define abort() abort_at( __FILE__, __LINE__ )
  63. #define assert(cond) assert_at( (cond), __FILE__, __LINE__ )
  64.  
  65. // local copy of write-pointer
  66. static uint16_t widx = 0;
  67.  
  68. // global var for write-pointer is located right after message ringbuffer
  69. #define ddr_msgbuf_end ( ddr.msgbuf + ddr.num_msgs )
  70. #define ddr_widx ( *(uint16_t volatile *)ddr_msgbuf_end )
  71.  
  72. // receive byte from uart
  73. static inline char uart_recv_byte()
  74. {
  75. for(;;) {
  76. uint8_t lsr = CT_UART.LSR;
  77. if( lsr & 0x1e )
  78. abort(); // receive-error occurred
  79. if( lsr & 0x01 )
  80. return (char) CT_UART.RBR;
  81. }
  82. }
  83.  
  84.  
  85. // receive CR-terminated line from uart
  86. static inline uint8_t uart_recv_line( char volatile msg[], uint8_t maxlen )
  87. {
  88. uint8_t len = 0;
  89.  
  90. for(;;) {
  91. char c = uart_recv_byte();
  92. if( c == '\r' )
  93. break; // found end of line
  94. if( len == maxlen )
  95. abort(); // line does not fit in buffer
  96. msg[ len++ ] = c;
  97. }
  98.  
  99. return len;
  100. }
  101.  
  102. int32_t abs(int16_t value){
  103. return value * ((value>0) - (value <0));
  104. }
  105.  
  106.  
  107. int16_t receive_measurement()
  108. {
  109. // allocate buffer at fixed address for debugging convenience
  110. static char volatile msg[8] __attribute__((location(0x1f00)));
  111.  
  112. // receive line from uart
  113. uint8_t len = uart_recv_line( msg, sizeof msg );
  114.  
  115. // verify length and prefix
  116. if( len != 8 || msg[0] != 'N' || (msg[1] != '+' && msg[1] != '-'))
  117. abort();
  118.  
  119. // parse the remainder as integer
  120. int16_t value = 0;
  121. uint8_t i;
  122. for( i = 2; i < len; i++ ) {
  123. if( msg[i] < '0' || msg[i] > '9' )
  124. abort();
  125. value = value * 10 + ( msg[i] - '0' );
  126. }
  127. if (msg[1] == '-')
  128. value *= -1;
  129.  
  130. return value;
  131. }
  132.  
  133.  
  134. void initialize()
  135. {
  136. // perform sanity-checking
  137. assert( 0x80000000 <= (uint32_t)ddr.msgbuf );
  138. assert( ddr.msgbuf < ddr_msgbuf_end );
  139. assert( ddr.msg_size == sizeof(Message) );
  140.  
  141. assert( ddr_widx == widx );
  142. assert( shmem.ridx == widx );
  143. }
  144.  
  145.  
  146. static inline uint16_t next_idx( uint16_t idx )
  147. {
  148. if( ++idx == ddr.num_msgs )
  149. idx = 0;
  150. return idx;
  151. }
  152.  
  153.  
  154. void send_message( uint32_t id, int16_t current_force,uint32_t current_position, int32_t input, int16_t output)
  155. {
  156. uint16_t next_widx = next_idx( widx );
  157.  
  158. if( next_widx == shmem.ridx ) {
  159. // can't send message, ringbuffer is full
  160. abort();
  161. }
  162.  
  163. Message volatile *msg = &ddr.msgbuf[ widx ];
  164.  
  165. // fill in contents of message
  166. msg->id = id;
  167. msg->position = current_position;
  168. msg->force = current_force;
  169. msg->timestamp = timestamp_cycles();
  170. msg->control_signal = input;
  171. msg->motor_effort = output;
  172. // update write-pointer
  173. ddr_widx = widx = next_widx;
  174. }
  175.  
  176. void main() {
  177. int32_t control_signal = 0;
  178. int32_t error[3];
  179. CT_UART.THR = 'S';
  180. CT_UART.THR = 'N';
  181. CT_UART.THR = '\r';
  182. initialize();
  183.  
  184. uint32_t id =0;
  185. uint32_t reference_count = *position_var; // initil reading from decoder as unit32
  186.  
  187. uint16_t counter = 0;
  188. gpio_set_one_low(&GPIO0,31);
  189.  
  190. // PID parameters
  191. int32_t Kp = (int)(10 * 0x010000) ;
  192. int32_t Ki = (int)(10 * 0x010000) ;
  193. int32_t Kd = (int)(10 * 0x010000) ;
  194.  
  195. int16_t A[3] = {0};
  196. A[0] = Kp + Ki + Kd;
  197. A[1] = -Kp -2*Kd;
  198. A[2] = Kd;
  199.  
  200.  
  201. while (true) {
  202. int16_t force = receive_measurement();
  203. uint32_t current_position = *position_var - reference_count;
  204. int16_t input_signal = shmem.signal[counter];
  205.  
  206.  
  207. // Control logic work in progress
  208. error[2] = error[1];
  209. error[1] = error[0];
  210. error[0] = input_signal + reference_count; // current reading from decoder
  211. error[0] = error[0] - current_position;
  212. control_signal += A[0] * error[0] + A[1] * error[1] + A[2] * error[2];
  213.  
  214. // check if motor direction must change
  215. if (control_signal < 0) {
  216. // place lower bound on control signal
  217. if (control_signal < -(4000 << 16))
  218. control_signal = -(4000 << 16);
  219. gpio_set_one_low(&GPIO0,31);
  220. } else {
  221. // place upper bound on control signal
  222. if (control_signal > (4000 << 16))
  223. control_signal = (4000 << 16);
  224. gpio_set_one_high(&GPIO0,31);
  225. }
  226.  
  227. // check for fault condition
  228. // if (position > 25000 && reference_count < 42949000)
  229. // EPWM1A = 0;
  230. // else
  231. EPWM1A = abs(control_signal) >> 16;
  232.  
  233. //report to python
  234. send_message( ++id,force, current_position, input_signal,control_signal);
  235. ++counter;
  236. // reset counter to enforce periodicy
  237. if (counter > 999){
  238. counter = 0;
  239. reference_count = *position_var; // initil reading from decoder as unit32
  240. }
  241. }
  242. }
  243.  
  244.  
  245.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement