Advertisement
DenseBrainMatrix

Untitled

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