Advertisement
Guest User

Untitled

a guest
Mar 15th, 2023
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.46 KB | None | 0 0
  1. #include <stdlib.h>
  2. #include <stdint.h>
  3. #include <stddef.h>
  4. #include "pru_uart.h"
  5. #include "pru_ecap.h"
  6. #include "sys_gpio.h"
  7.  
  8. // define PWM inputs for motor controll
  9. #define EPWM1A ( *(uint16_t volatile *)0x48302212 )
  10. #define EPWM1B ( *(uint16_t volatile *)0x48302214 )
  11.  
  12. // encoder position in other PRU core's memory
  13. #define position_var ((uint32_t const volatile *)0x00002000)
  14.  
  15. struct Message {
  16. uint32_t id;
  17. uint32_t timestamp;
  18. int32_t control_signal;
  19. int32_t motor_effort;
  20. int16_t force;
  21. int16_t cycle_count;
  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. uint32_t time;
  36. // read-pointer updated by python
  37. uint16_t ridx;
  38. uint16_t cycle_limit;
  39. uint16_t time_limit;
  40. uint16_t signal_length;
  41. uint16_t signal[2000];
  42. };
  43.  
  44. far struct DDRLayout ddr __attribute__((location(0x10000))) = {};
  45. far struct SharedVars volatile shmem __attribute__((location(0x10100))) = {};
  46.  
  47. static inline uint32_t timestamp_cycles()
  48. {
  49. return CT_ECAP.TSCTR;
  50. }
  51.  
  52. // for easier debugging, record where in the source code we halted
  53. __attribute__((noreturn))
  54. void abort_at( char const *file, int line )
  55. {
  56. shmem.abort_file = file;
  57. shmem.abort_line = line;
  58. for(;;) __halt();
  59. }
  60.  
  61. static inline void assert_at( bool cond, char const *file, int line )
  62. {
  63. if( ! cond )
  64. abort_at( file, line );
  65. }
  66.  
  67. #define abort() abort_at( __FILE__, __LINE__ )
  68. #define assert(cond) assert_at( (cond), __FILE__, __LINE__ )
  69.  
  70. // local copy of write-pointer
  71. static uint16_t widx = 0;
  72.  
  73. // global var for write-pointer is located right after message ringbuffer
  74. #define ddr_msgbuf_end ( ddr.msgbuf + ddr.num_msgs )
  75. #define ddr_widx ( *(uint16_t volatile *)ddr_msgbuf_end )
  76.  
  77. // receive byte from uart
  78. static inline char uart_recv_byte()
  79. {
  80. for(;;) {
  81. uint8_t lsr = CT_UART.LSR;
  82. if( lsr & 0x1e )
  83. abort(); // receive-error occurred
  84. if( lsr & 0x01 )
  85. return (char) CT_UART.RBR;
  86. }
  87. }
  88.  
  89.  
  90. // receive CR-terminated line from uart
  91. static inline uint8_t uart_recv_line( char volatile msg[], uint8_t maxlen )
  92. {
  93. uint8_t len = 0;
  94.  
  95. for(;;) {
  96. char c = uart_recv_byte();
  97. if( c == '\r' )
  98. break; // found end of line
  99. if( len == maxlen )
  100. abort(); // line does not fit in buffer
  101. msg[ len++ ] = c;
  102. }
  103.  
  104. return len;
  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, int32_t input, int32_t output, uint16_t cycle)
  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->force = current_force;
  169. msg->timestamp = timestamp_cycles();
  170. msg->control_signal = input;
  171. msg->motor_effort = output;
  172. msg->cycle_count = cycle;
  173. // update write-pointer
  174. ddr_widx = widx = next_widx;
  175. }
  176.  
  177. void main() {
  178. int32_t control_signal = 0;
  179. int32_t error[3];
  180. CT_UART.THR = 'S';
  181. CT_UART.THR = 'N';
  182. CT_UART.THR = '\r';
  183. initialize();
  184.  
  185. uint32_t id =0;
  186. int16_t reference_force = receive_measurement(); // initil reading from load cell
  187.  
  188. uint16_t counter = 0;
  189. gpio_set_one_low(&GPIO0,31);
  190.  
  191. // PID parameers
  192. int32_t Kp = (int)(10 * (1 << 16)) ; // 20
  193. int32_t Ki = (int)(0 * (1 << 16)) ; // 0.5
  194. int32_t Kd = (int)(0 * (1 << 16)) ;// 0.4
  195.  
  196. int32_t A[3] = {0};
  197. A[0] = Kp + Ki + Kd;
  198. A[1] = -Kp -2*Kd;
  199. A[2] = Kd;
  200.  
  201. uint16_t cycle_count = 0;
  202. bool running = true;
  203. uint16_t last_cycle = shmem.cycle_limit;
  204. uint16_t time_limit = shmem.time_limit;
  205. uint16_t signal_length = shmem.signal_length;
  206.  
  207. while (running) {
  208. if (cycle_count <= last_cycle)
  209. {
  210.  
  211. int16_t force = receive_measurement();
  212. int32_t input_signal = shmem.signal[counter];
  213.  
  214. // Control logic work in progress
  215. error[2] = error[1];
  216. error[1] = error[0];
  217. error[0] = input_signal + reference_force; // current reading from decoder
  218. error[0] = error[0] - force;
  219. control_signal += A[0] * error[0] + A[1] * error[1] + A[2] * error[2];
  220.  
  221. int32_t output_signal = 0;
  222. // check if motor direction must change
  223. if (control_signal < 0) {
  224. // place lower bound on control signal
  225. //if (control_signal < -(5000 << 16))
  226. // control_signal = -(5000 << 16);
  227. output_signal = -(control_signal >> 16);
  228. //output_signal *= -1;
  229. gpio_set_one_high(&GPIO0,31);
  230. } else {
  231. // place upper bound on control signal
  232. //if (control_signal > (5000 << 16))
  233. // control_signal = (5000 << 16);
  234. output_signal = (control_signal >> 16);
  235. gpio_set_one_low(&GPIO0,31);
  236. }
  237. EPWM1A = abs(control_signal) >> 16;
  238. //report to python
  239. send_message( ++id,force, input_signal,output_signal,cycle_count);
  240. ++counter;
  241. // reset counter to enforce periodicy
  242. if (counter > signal_length){
  243. counter = 0;
  244. ++cycle_count;
  245. }
  246. } else {
  247.  
  248. EPWM1A = 0;
  249.  
  250. int16_t force = receive_measurement();
  251. int32_t input_signal = shmem.signal[counter];
  252. int32_t output_signal = 0;
  253. send_message( ++id,force , input_signal,output_signal,cycle_count);
  254. }
  255. }
  256. }
  257.  
  258.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement