Siegurd

pru_adc_firmware.c

Oct 16th, 2023
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.98 KB | None | 0 0
  1. // https://git.ti.com/cgit/pru-software-support-package/pru-software-support-package/tree/examples/am335x/PRU_ADC_onChip/pru_adc_firmware.c
  2.  
  3. /*
  4. * Copyright (C) 2018-2021 Texas Instruments Incorporated - http://www.ti.com/
  5. *
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * * Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * * Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * * Neither the name of Texas Instruments Incorporated nor the names of
  20. * its contributors may be used to endorse or promote products derived
  21. * from this software without specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  24. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  25. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  26. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  27. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  28. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  29. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  30. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  31. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  32. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  33. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34. */
  35.  
  36. #include <stdint.h>
  37. #include <stdio.h>
  38. #include <pru_cfg.h>
  39. #include <pru_intc.h>
  40. #include <sys_tscAdcSs.h>
  41. #include <rsc_types.h>
  42. #include <pru_rpmsg.h>
  43. #include "resource_table.h"
  44. #include "intc_map_0.h"
  45.  
  46. volatile register uint32_t __R31;
  47.  
  48. /* Host-0 Interrupt sets bit 30 in register R31 */
  49. #define HOST_INT ((uint32_t) 1 << 30)
  50.  
  51. /*
  52. * The PRU-ICSS system events used for RPMsg are defined in the Linux devicetree
  53. * PRU0 uses system event 16 (To ARM) and 17 (From ARM)
  54. * PRU1 uses system event 18 (To ARM) and 19 (From ARM)
  55. */
  56. #define TO_ARM_HOST 16
  57. #define FROM_ARM_HOST 17
  58.  
  59. /*
  60. * Using the name 'rpmsg-pru' will probe the rpmsg_pru driver found
  61. * at linux-x.y.z/drivers/rpmsg/rpmsg_pru.c
  62. */
  63. #define CHAN_NAME "rpmsg-pru"
  64. #define CHAN_DESC "Channel 30"
  65. #define CHAN_PORT 30
  66.  
  67. /*
  68. * Used to make sure the Linux drivers are ready for RPMsg communication
  69. * Found at linux-x.y.z/include/uapi/linux/virtio_config.h
  70. */
  71. #define VIRTIO_CONFIG_S_DRIVER_OK 4
  72.  
  73. /* Control Module registers to enable the ADC peripheral */
  74. #define CM_WKUP_CLKSTCTRL (*((volatile unsigned int *)0x44E00400))
  75. #define CM_WKUP_ADC_TSC_CLKCTRL (*((volatile unsigned int *)0x44E004BC))
  76.  
  77. /* payload receives RPMsg message */
  78. char payload[RPMSG_MESSAGE_SIZE];
  79.  
  80. /* shared_struct is used to pass data between ARM and PRU */
  81. typedef struct shared_struct{
  82. uint16_t voltage;
  83. uint16_t channel;
  84. } shared_struct;
  85.  
  86. void init_adc();
  87. uint16_t read_adc(uint16_t adc_chan);
  88.  
  89. void main(void)
  90. {
  91. struct pru_rpmsg_transport transport;
  92. uint16_t src, dst, len;
  93. volatile uint8_t *status;
  94. struct shared_struct message;
  95.  
  96. /*
  97. * Allow OCP master port access by the PRU so the PRU can read
  98. * external memories
  99. */
  100. CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
  101.  
  102. init_adc();
  103.  
  104. /*
  105. * Clear the status of the PRU-ICSS system event that the ARM will
  106. * use to 'kick' us
  107. */
  108. CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;
  109.  
  110. /* Make sure the Linux drivers are ready for RPMsg communication */
  111. status = &resourceTable.rpmsg_vdev.status;
  112. while (!(*status & VIRTIO_CONFIG_S_DRIVER_OK)) {
  113. /* Optional: implement timeout logic */
  114. };
  115.  
  116. /* Initialize the RPMsg transport structure */
  117. pru_rpmsg_init(&transport, &resourceTable.rpmsg_vring0,
  118. &resourceTable.rpmsg_vring1, TO_ARM_HOST, FROM_ARM_HOST);
  119.  
  120. /*
  121. * Create the RPMsg channel between the PRU and ARM user space using
  122. * the transport structure.
  123. */
  124. while (pru_rpmsg_channel(RPMSG_NS_CREATE, &transport, CHAN_NAME,
  125. CHAN_PORT) != PRU_RPMSG_SUCCESS) {
  126. /* Optional: implement timeout logic */
  127. };
  128.  
  129. while (1) {
  130. /* Check register R31 bit 30 to see if the ARM has kicked us */
  131. if (!(__R31 & HOST_INT))
  132. continue;
  133.  
  134. /* Clear the event status */
  135. CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;
  136.  
  137. /*
  138. * Receive available messages.
  139. * Multiple messages can be sent per kick.
  140. */
  141. while (pru_rpmsg_receive(&transport, &src, &dst,
  142. payload, &len) == PRU_RPMSG_SUCCESS) {
  143.  
  144. /* ARM sends a message using shared_struct */
  145. message.channel = ((shared_struct *)payload)->channel;
  146. message.voltage = read_adc(message.channel);
  147.  
  148. /*
  149. * Send reply message to the address that sent
  150. * the initial message
  151. */
  152. pru_rpmsg_send(&transport, dst, src, &message,
  153. sizeof(message));
  154. }
  155. }
  156. }
  157.  
  158. void init_adc()
  159. {
  160.  
  161. /* set the always on clock domain to NO_SLEEP. Enable ADC_TSC clock */
  162. while (!(CM_WKUP_ADC_TSC_CLKCTRL == 0x02)) {
  163. CM_WKUP_CLKSTCTRL = 0;
  164. CM_WKUP_ADC_TSC_CLKCTRL = 0x02;
  165. /* Optional: implement timeout logic. */
  166. }
  167.  
  168. /*
  169. * Set the ADC_TSC CTRL register.
  170. * Disable TSC_ADC_SS module so we can program it.
  171. * Set step configuration registers to writable.
  172. */
  173. ADC_TSC.CTRL_bit.ENABLE = 0;
  174. ADC_TSC.CTRL_bit.STEPCONFIG_WRITEPROTECT_N_ACTIVE_LOW = 1;
  175.  
  176. /*
  177. * set the ADC_TSC STEPCONFIG1 register for channel 5
  178. * Mode = 0; SW enabled, one-shot
  179. * Averaging = 0x3; 8 sample average
  180. * SEL_INP_SWC_3_0 = 0x4 = Channel 5
  181. * SEL_INM_SWC_3_0 = 1xxx = VREFN (reduces noise in single ended mode)
  182. * use FIFO0
  183. */
  184. ADC_TSC.STEPCONFIG1_bit.MODE = 0;
  185. ADC_TSC.STEPCONFIG1_bit.AVERAGING = 3;
  186. ADC_TSC.STEPCONFIG1_bit.SEL_INP_SWC_3_0 = 4;
  187. ADC_TSC.STEPCONFIG1_bit.SEL_INM_SWC_3_0 = 8;
  188. ADC_TSC.STEPCONFIG1_bit.FIFO_SELECT = 0;
  189.  
  190. /*
  191. * set the ADC_TSC STEPCONFIG2 register for channel 6
  192. * Mode = 0; SW enabled, one-shot
  193. * Averaging = 0x3; 8 sample average
  194. * SEL_INP_SWC_3_0 = 0x5 = Channel 6
  195. * SEL_INM_SWC_3_0 = 1xxx = VREFN (reduces noise in single ended mode)
  196. * use FIFO0
  197. */
  198. ADC_TSC.STEPCONFIG2_bit.MODE = 0;
  199. ADC_TSC.STEPCONFIG2_bit.AVERAGING = 3;
  200. ADC_TSC.STEPCONFIG2_bit.SEL_INP_SWC_3_0 = 5;
  201. ADC_TSC.STEPCONFIG2_bit.SEL_INM_SWC_3_0 = 8;
  202. ADC_TSC.STEPCONFIG2_bit.FIFO_SELECT = 0;
  203.  
  204. /*
  205. * set the ADC_TSC STEPCONFIG3 register for channel 7
  206. * Mode = 0; SW enabled, one-shot
  207. * Averaging = 0x3; 8 sample average
  208. * SEL_INP_SWC_3_0 = 0x6 = Channel 7
  209. * SEL_INM_SWC_3_0 = 1xxx = VREFN (reduces noise in single ended mode)
  210. * use FIFO0
  211. */
  212. ADC_TSC.STEPCONFIG3_bit.MODE = 0;
  213. ADC_TSC.STEPCONFIG3_bit.AVERAGING = 3;
  214. ADC_TSC.STEPCONFIG3_bit.SEL_INP_SWC_3_0 = 6;
  215. ADC_TSC.STEPCONFIG3_bit.SEL_INM_SWC_3_0 = 8;
  216. ADC_TSC.STEPCONFIG3_bit.FIFO_SELECT = 0;
  217.  
  218. /*
  219. * set the ADC_TSC STEPCONFIG4 register for channel 8
  220. * Mode = 0; SW enabled, one-shot
  221. * Averaging = 0x3; 8 sample average
  222. * SEL_INP_SWC_3_0 = 0x7= Channel 8
  223. * SEL_INM_SWC_3_0 = 1xxx = VREFN (reduces noise in single ended mode)
  224. * use FIFO0
  225. */
  226. ADC_TSC.STEPCONFIG4_bit.MODE = 0;
  227. ADC_TSC.STEPCONFIG4_bit.AVERAGING = 3;
  228. ADC_TSC.STEPCONFIG4_bit.SEL_INP_SWC_3_0 = 7;
  229. ADC_TSC.STEPCONFIG4_bit.SEL_INM_SWC_3_0 = 8;
  230. ADC_TSC.STEPCONFIG4_bit.FIFO_SELECT = 0;
  231.  
  232. /*
  233. * set the ADC_TSC CTRL register
  234. * set step configuration registers to protected
  235. * store channel ID tag if needed for debug
  236. * Enable TSC_ADC_SS module
  237. */
  238. ADC_TSC.CTRL_bit.STEPCONFIG_WRITEPROTECT_N_ACTIVE_LOW = 0;
  239. ADC_TSC.CTRL_bit.STEP_ID_TAG = 1;
  240. ADC_TSC.CTRL_bit.ENABLE = 1;
  241. }
  242.  
  243. uint16_t read_adc(uint16_t adc_chan)
  244. {
  245. /*
  246. * Clear FIFO0 by reading from it
  247. * We are using single-shot mode.
  248. * It should not usually enter the for loop
  249. */
  250. uint32_t count = ADC_TSC.FIFO0COUNT;
  251. uint32_t data;
  252. uint32_t i;
  253. for (i = 0; i < count; i++) {
  254. data = ADC_TSC.FIFO0DATA;
  255. }
  256.  
  257. /* read from the specified ADC channel */
  258. switch (adc_chan) {
  259. case 5 :
  260. ADC_TSC.STEPENABLE_bit.STEP1 = 1;
  261. case 6 :
  262. ADC_TSC.STEPENABLE_bit.STEP2 = 1;
  263. case 7 :
  264. ADC_TSC.STEPENABLE_bit.STEP3 = 1;
  265. case 8 :
  266. ADC_TSC.STEPENABLE_bit.STEP4 = 1;
  267. default :
  268. /*
  269. * this error condition should not occur because of
  270. * checks in userspace code
  271. */
  272. ADC_TSC.STEPENABLE_bit.STEP1 = 1;
  273. }
  274.  
  275. while (ADC_TSC.FIFO0COUNT == 0) {
  276. /*
  277. * loop until value placed in fifo.
  278. * Optional: implement timeout logic.
  279. *
  280. * Other potential options include:
  281. * - configure PRU to receive an ADC interrupt. Note that
  282. * END_OF_SEQUENCE does not mean that the value has been
  283. * loaded into the FIFO yet
  284. * - perform other actions, and periodically poll for
  285. * FIFO0COUNT > 0
  286. */
  287. }
  288.  
  289. /* read the voltage */
  290. uint16_t voltage = ADC_TSC.FIFO0DATA_bit.ADCDATA;
  291.  
  292. return voltage;
  293. }
  294.  
Advertisement
Add Comment
Please, Sign In to add comment