d_quadEnc.c
Go to the documentation of this file.
1 /*
2 MIT LICENSE
3 
4 Copyright 2014-2019 Inertial Sense, Inc. - http://inertialsense.com
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
7 
8 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9 
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT, IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 */
12 
13 #include <asf.h>
14 #include "d_quadEnc.h"
15 #include "conf_d_quadEnc.h"
16 
17 
18 //Use of index signal is not support at this time. Needs setup for pin and reading values
19 #define QDEC_USE_INDEX 0
20 
21 static void quadEncSetModePosition(Tc *const timercounter, uint32_t ID_timercounter)
22 {
23  //Enable the QDEC channel clocks
24  sysclk_enable_peripheral_clock(ID_timercounter); //Channel 0
25 #if QDEC_USE_INDEX
26  sysclk_enable_peripheral_clock(ID_timercounter + 1); //Channel 1
27 #endif
28 
29  //Init TC channel 0 to QDEC Position mode
30  tc_init(timercounter, 0,
32  | TC_CMR_ETRGEDG_RISING /* To clear the counter on a rising edge of the TIOA signal*/
33  | TC_CMR_ABETRG /* To select TIOA as a trigger for this channel 0 */
34  );
35 
36 #if QDEC_USE_INDEX
37  //Init TC channel 1 to QDEC Rotation mode
38  tc_init(timercounter, 1,
39  /* QDEC Clock Selection */
41  );
42 #endif
43 
44  //Enable TC QDEC channel 0 in QDEC Position mode
45  tc_set_block_mode(timercounter, TC_BMR_QDEN /* QDEC mode enabled */
46  | TC_BMR_POSEN /* Position measure is enabled */
47  | TC_BMR_EDGPHA /* Detect quadrature on both PHA and PHB (4X decoding)*/
48  | (0<< TC_BMR_MAXFILT_Pos) /* enable filter on input signal*/
49  );
50 
51  tc_start(timercounter, 0); //For position measurement
52 #if QDEC_USE_INDEX
53  tc_start(timercounter, 1); //For rotation measurement
54 #endif
55 }
56 
57 static uint32_t speed_capture[2] = {0, 0};
58 static uint32_t speed_capture_timeMs = 0;
59 
61 {
62  static bool running = false;
63 
64  uint32_t status = tc_get_status(TCCAP0_SPD, TCCAP0_SPD_CHANNEL);
65 
66  if ((status & TC_SR_LDRAS) != 0)
67  {
68  if(running)
69  {
72  }
73  else
74  {
75  //first read after stopping is invalid
76  tc_read_ra(TCCAP0_SPD, TCCAP0_SPD_CHANNEL); //discard read
77  running = true;
78  }
79  }
80 
81  if ((status & TC_SR_COVFS) != 0)
82  {
83  //Timer overflow so we assume we are not moving
84  speed_capture[0] = 0;
86  running = false;
87  }
88 }
89 
91 {
92  static bool running = false;
93 
94  uint32_t status = tc_get_status(TCCAP1_SPD, TCCAP1_SPD_CHANNEL);
95 
96  if ((status & TC_SR_LDRAS) != 0)
97  {
98  if(running)
99  {
102  }
103  else
104  {
105  //first read after stopping is invalid
106  tc_read_ra(TCCAP1_SPD, TCCAP1_SPD_CHANNEL); //discard read
107  running = true;
108  }
109  }
110 
111  if ((status & TC_SR_COVFS) != 0)
112  {
113  //Timer overflow so we assume we are not moving
114  speed_capture[1] = 0;
116  running = false;
117  }
118 }
119 
120 static void quadEncSetModeSpeed(Tc *const timercounter, int timerchannel, int timerirq, uint32_t ID_timercounter)
121 {
122  //Enable the TC channel clock
123  sysclk_enable_peripheral_clock(ID_timercounter);
124 
125  if(!pmc_is_pck_enabled(PMC_PCK_6))
126  {
127  pmc_disable_pck(PMC_PCK_6);
128  pmc_switch_pck_to_mainck(PMC_PCK_6, PMC_PCK_PRES(239));
129  pmc_enable_pck(PMC_PCK_6);
130  }
131 
132  // Init TC to capture mode. 20us per counter LSB.
133  tc_init(timercounter, timerchannel,
134  TC_CMR_TCCLKS_TIMER_CLOCK1 /* Clock Selection */
135  | TC_CMR_LDRA_EDGE /* RA Loading: rising edge of TIOA */
136  | TC_CMR_ABETRG /* External Trigger: TIOA */
137  | TC_CMR_ETRGEDG_EDGE /* External Trigger Edge: rising */
138  );
139 
140  // Setup capture and overflow interrupt
141  NVIC_DisableIRQ(timerirq);
142  NVIC_ClearPendingIRQ(timerirq);
144  NVIC_EnableIRQ(timerirq);
145  tc_enable_interrupt(timercounter, timerchannel, TC_IER_LDRAS | TC_IER_COVFS);
146 
147  tc_start(timercounter, timerchannel);
148 }
149 
150 void quadEncInit(void)
151 {
152  /**** Configure pins ****/
153  // Left Encoder - Position
158 
159  // Left Encoder - Speed
162 
163  // Right Encoder - Position
168 
169  // Right Encoder - Speed
172 
173  /**** Setup hardware ****/
176 
179 }
180 
181 void quadEncReadPositionAll(int *pos0, bool *dir0, int *pos1, bool *dir1)
182 {
183  int16_t cv;
184 
186 
187  cv = QE0_POS->TC_CHANNEL[0].TC_CV;
188  *pos0 = cv;
189  *dir0 = (QE0_POS->TC_QISR & TC_QISR_DIR) / TC_QISR_DIR;
190 
191  cv = QE1_POS->TC_CHANNEL[0].TC_CV;
192  *pos1 = cv;
193  *dir1 = (QE1_POS->TC_QISR & TC_QISR_DIR) / TC_QISR_DIR;
194 
196 }
197 
198 void quadEncReadSpeedAll(uint32_t *speed0, uint32_t *speed1)
199 {
201 
202  uint32_t dtMs = time_msec() - speed_capture_timeMs;
203  if(dtMs < 100)
204  {
205  *speed0 = speed_capture[0];
206  *speed1 = speed_capture[1];
207  }
208  else
209  { // Return zero if encoder pulses occur slower than 100ms
210  *speed0 = 0;
211  *speed1 = 0;
212  }
213 
215 }
216 
218 {
219 #if 1 //quadEnc testing
220 
221  udi_cdc_write_buf("Running\r\n", 9);
222  quadEncInit();
223 
224  while(1)
225  {
226  #define BUF_SIZE 100
227  char str[BUF_SIZE];
228  int chL, chR;
229  bool dirL, dirR;
230  int speedL, speedR;
231 
232  quadEncReadPositionAll(&chL, &dirL, &chR, &dirR);
233  quadEncReadSpeedAll((uint32_t*)&speedL, (uint32_t*)&speedR);
234 
235  // Set velocity direction
236  if(dirL)
237  {
238  speedL = -speedL;
239  }
240  if(dirR)
241  {
242  speedR = -speedR;
243  }
244 
245  int len = SNPRINTF(str, BUF_SIZE, "ch0 %c %7d %7d ch1 %c %7d %7d\r\n",
246  dirL ? 'R':'F', chL, (int)speedL,
247  dirR ? 'R':'F', chR, (int)speedR);
248  udi_cdc_write_buf(str, len);
249 
250  vTaskDelay(200);
251  }
252 
253 #endif //END quadEnc testing
254 }
#define TC_BMR_QDEN
(TC_BMR) Quadrature Decoder Enabled
#define TC_BMR_EDGPHA
(TC_BMR) Edge on PHA Count Mode
#define PIN_TCCAP1_SPD_MUX
#define QE0_POS
#define PIN_QE1_POS_PHA_MUX
uint32_t time_msec(void)
Definition: d_time.c:95
#define TCCAP1_SPD_IRQn
static void ioport_set_pin_mode(ioport_pin_t pin, ioport_mode_t mode)
Set pin mode for one single IOPORT pin.
Definition: ioport.h:217
void quadEncInit(void)
Initialize quadrature encoder driver.
Definition: d_quadEnc.c:150
static uint32_t speed_capture_timeMs
Definition: d_quadEnc.c:58
void pmc_enable_pck(uint32_t ul_id)
Enable the specified programmable clock.
Definition: pmc.c:1020
static int running
#define taskEXIT_CRITICAL()
Definition: task.h:194
void TCCAP1_SPD_Handler(void)
Definition: d_quadEnc.c:90
#define TC_IER_COVFS
(TC_IER) Counter Overflow
void quadEncReadSpeedAll(uint32_t *speed0, uint32_t *speed1)
Definition: d_quadEnc.c:198
uint32_t pmc_is_pck_enabled(uint32_t ul_id)
Check if the specified programmable clock is enabled.
Definition: pmc.c:1059
#define PIN_QE0_POS_PHB
#define PIN_QE1_POS_PHB
#define TC_QISR_DIR
(TC_QISR) Direction
#define TCCAP0_SPD_IRQn
static void quadEncSetModeSpeed(Tc *const timercounter, int timerchannel, int timerirq, uint32_t ID_timercounter)
Definition: d_quadEnc.c:120
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
Set Interrupt Priority.
Definition: core_cm7.h:1766
static uint32_t speed_capture[2]
Definition: d_quadEnc.c:57
void quadEncReadPositionAll(int *pos0, bool *dir0, int *pos1, bool *dir1)
Reads the current position of the encoders.
Definition: d_quadEnc.c:181
#define ID_TCCAP0_SPD
#define PIN_TCCAP0_SPD
#define TC_IER_LDRAS
(TC_IER) RA Loading
#define TC_CMR_ETRGEDG_EDGE
(TC_CMR) Each edge
#define TC_CMR_ETRGEDG_RISING
(TC_CMR) Rising edge
#define QE1_POS
#define PIN_TCCAP0_SPD_MUX
void tc_start(Tc *p_tc, uint32_t ul_channel)
Start the TC clock on the specified channel.
Definition: tc.c:169
void pmc_disable_pck(uint32_t ul_id)
Disable the specified programmable clock.
Definition: pmc.c:1030
static void quadEncSetModePosition(Tc *const timercounter, uint32_t ID_timercounter)
Definition: d_quadEnc.c:21
#define PIN_QE1_POS_PHB_MUX
iram_size_t udi_cdc_write_buf(const void *buf, iram_size_t size)
Writes a RAM buffer on CDC line.
Definition: udi_cdc.c:1146
#define PIN_QE0_POS_PHA
__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
Disable External Interrupt.
Definition: core_cm7.h:1696
#define TC_CMR_LDRA_EDGE
(TC_CMR) Each edge of TIOA
#define TC_CMR_TCCLKS_XC0
(TC_CMR) Clock selected: XC0
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
Enable External Interrupt.
Definition: core_cm7.h:1683
void tc_init(Tc *p_tc, uint32_t ul_channel, uint32_t ul_mode)
Configure TC for timer, waveform generation, or capture.
Definition: tc.c:70
#define PIN_QE0_POS_PHA_MUX
#define TC_SR_LDRAS
(TC_SR) RA Loading Status (cleared on read)
#define TC_SR_COVFS
(TC_SR) Counter Overflow Status (cleared on read)
uint32_t tc_read_ra(Tc *p_tc, uint32_t ul_channel)
Read TC Register A (RA) on the specified channel.
Definition: tc.c:227
#define TCCAP1_SPD
#define PMC_PCK_PRES(value)
__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
Clear Pending Interrupt.
Definition: core_cm7.h:1736
#define SNPRINTF
Definition: ISConstants.h:146
#define PIN_QE0_POS_PHB_MUX
uint32_t tc_get_status(Tc *p_tc, uint32_t ul_channel)
Get the current status for the specified TC channel.
Definition: tc.c:445
#define TCCAP1_SPD_CHANNEL
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
#define PIN_QE1_POS_PHA
#define TC_BMR_POSEN
(TC_BMR) Position Enabled
#define taskENTER_CRITICAL()
Definition: task.h:179
#define ID_QE0_POS
void tc_enable_interrupt(Tc *p_tc, uint32_t ul_channel, uint32_t ul_sources)
Enable the TC interrupts on the specified channel.
Definition: tc.c:362
void test_quad_encoders(void)
Definition: d_quadEnc.c:217
#define TCCAP0_SPD_CHANNEL
#define ID_QE1_POS
uint32_t pmc_switch_pck_to_mainck(uint32_t ul_id, uint32_t ul_pres)
Switch programmable clock source selection to main clock.
Definition: pmc.c:898
#define PIN_TCCAP1_SPD
void vTaskDelay(const TickType_t xTicksToDelay) PRIVILEGED_FUNCTION
static void sysclk_enable_peripheral_clock(uint32_t ul_id)
Enable a peripheral&#39;s clock.
#define ID_TCCAP1_SPD
Autogenerated API include file for the Atmel Software Framework (ASF)
void TCCAP0_SPD_Handler(void)
Definition: d_quadEnc.c:60
#define TCCAP0_SPD
static void ioport_disable_pin(ioport_pin_t pin)
Disable IOPORT pin, based on a pin created with IOPORT_CREATE_PIN().
Definition: ioport.h:179
void tc_set_block_mode(Tc *p_tc, uint32_t ul_blockmode)
Configure the TC Block mode.
Definition: tc.c:123
#define TC_CMR_ABETRG
(TC_CMR) TIOA or TIOB External Trigger Selection
#define TC_CMR_TCCLKS_TIMER_CLOCK1
(TC_CMR) Clock selected: internal PCK6 clock signal (from PMC)
#define BUF_SIZE


inertial_sense_ros
Author(s):
autogenerated on Sun Feb 28 2021 03:17:57