File indexing completed on 2025-05-11 08:22:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <libcpu/am335x.h>
0037 #include <stdio.h>
0038 #include <stdlib.h>
0039 #include <bsp/gpio.h>
0040 #include <bsp/bbb-gpio.h>
0041 #include <bsp.h>
0042 #include <bsp/pwmss.h>
0043 #include <bsp/qep.h>
0044 #include <bsp/beagleboneblack.h>
0045
0046
0047
0048
0049
0050 static bbb_eqep bbb_eqep_table[ BBB_PWMSS_COUNT ] =
0051 {
0052 {
0053 .pwmss_id = BBB_PWMSS0,
0054 .mmio_base = AM335X_EQEP_0_REGS,
0055 .irq = AM335X_INT_eQEP0INT,
0056 .timer_callback = NULL,
0057 .user = NULL,
0058 .count_mode = QUADRATURE_COUNT,
0059 .quadrature_mode = ABSOLUTE,
0060 .invert_qa = 0,
0061 .invert_qb = 0,
0062 .invert_qi = 0,
0063 .invert_qs = 0,
0064 .swap_inputs = 0
0065 },
0066 {
0067 .pwmss_id = BBB_PWMSS1,
0068 .mmio_base = AM335X_EQEP_1_REGS,
0069 .irq = AM335X_INT_eQEP1INT,
0070 .timer_callback = NULL,
0071 .user = NULL,
0072 .count_mode = QUADRATURE_COUNT,
0073 .quadrature_mode = ABSOLUTE,
0074 .invert_qa = 0,
0075 .invert_qb = 0,
0076 .invert_qi = 0,
0077 .invert_qs = 0,
0078 .swap_inputs = 0
0079 },
0080 {
0081 .pwmss_id = BBB_PWMSS2,
0082 .mmio_base = AM335X_EQEP_2_REGS,
0083 .irq = AM335X_INT_eQEP2INT,
0084 .timer_callback = NULL,
0085 .user = NULL,
0086 .count_mode = QUADRATURE_COUNT,
0087 .quadrature_mode = ABSOLUTE,
0088 .invert_qa = 0,
0089 .invert_qb = 0,
0090 .invert_qi = 0,
0091 .invert_qs = 0,
0092 .swap_inputs = 0
0093 }
0094 };
0095
0096
0097 static void beagle_eqep_irq_handler(void *arg)
0098 {
0099 uint16_t flags;
0100 int32_t position = 0;
0101 bbb_eqep* eqep = arg;
0102
0103
0104
0105 flags = REG16(eqep->mmio_base + AM335x_EQEP_QFLG) & AM335x_EQEP_QFLG_MASK;
0106
0107 if (flags & AM335x_EQEP_QFLG_UTO && eqep->timer_callback != NULL) {
0108
0109 position = beagle_qep_get_position(eqep->pwmss_id);
0110 eqep->timer_callback(eqep->pwmss_id, position, eqep->user);
0111 }
0112
0113
0114 REG16(eqep->mmio_base + AM335x_EQEP_QCLR) = flags;
0115 }
0116
0117 rtems_status_code beagle_qep_init(BBB_PWMSS pwmss_id)
0118 {
0119 rtems_status_code sc;
0120 uint16_t qdecctl;
0121
0122 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0123 return RTEMS_INVALID_ID;
0124 }
0125 bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
0126
0127 sc = pwmss_module_clk_config(eqep->pwmss_id);
0128 if (sc != RTEMS_SUCCESSFUL) {
0129
0130 return sc;
0131 }
0132
0133
0134 REG(eqep->mmio_base + AM335X_PWMSS_CLKCONFIG) |= AM335x_EQEP_CLK_EN;
0135
0136
0137 sc = rtems_interrupt_handler_install(
0138 eqep->irq,
0139 NULL,
0140 RTEMS_INTERRUPT_UNIQUE,
0141 (rtems_interrupt_handler)beagle_eqep_irq_handler,
0142 (void*)eqep
0143 );
0144
0145
0146
0147 qdecctl = 0;
0148 if (eqep->count_mode <= 3) {
0149 qdecctl |= eqep->count_mode << 14;
0150
0151
0152
0153
0154 if (eqep->count_mode >= 2) {
0155 qdecctl |= AM335x_EQEP_QDECCTL_XCR;
0156 }
0157 }
0158
0159
0160 if (eqep->swap_inputs == 1) {
0161 qdecctl |= AM335x_EQEP_QDECCTL_SWAP;
0162 }
0163
0164 if (eqep->invert_qa == 1) {
0165 qdecctl |= AM335x_EQEP_QDECCTL_QAP;
0166 }
0167
0168 if (eqep->invert_qb == 1) {
0169 qdecctl |= AM335x_EQEP_QDECCTL_QBP;
0170 }
0171
0172 if (eqep->invert_qi == 1) {
0173 qdecctl |= AM335x_EQEP_QDECCTL_QIP;
0174
0175 }
0176
0177 if (eqep->invert_qs == 1) {
0178 qdecctl |= AM335x_EQEP_QDECCTL_QSP;
0179 }
0180
0181
0182 REG16(eqep->mmio_base + AM335x_EQEP_QDECCTL) = qdecctl;
0183
0184 REG(eqep->mmio_base + AM335x_EQEP_QPOSINIT) = 0;
0185
0186 REG(eqep->mmio_base + AM335x_EQEP_QPOSMAX) = ~0;
0187
0188 REG(eqep->mmio_base + AM335x_EQEP_QPOSCNT) = 0;
0189
0190 REG16(eqep->mmio_base + AM335x_EQEP_QEINT) |= AM335x_EQEP_QEINT_UTO;
0191
0192
0193
0194
0195
0196
0197
0198
0199 uint32_t value = AM335x_EQEP_QEPCTL_QCLM | AM335x_EQEP_QEPCTL_IEL |
0200 AM335x_EQEP_QEPCTL_PHEN | AM335x_EQEP_QEPCTL_SWI;
0201
0202
0203 REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) = value;
0204
0205 return RTEMS_SUCCESSFUL;
0206 }
0207
0208 rtems_status_code beagle_qep_enable(BBB_PWMSS pwmss_id)
0209 {
0210 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0211 return RTEMS_INVALID_ID;
0212 }
0213 const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
0214
0215 REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) |= AM335x_EQEP_QEPCTL_PHEN;
0216
0217 return RTEMS_SUCCESSFUL;
0218 }
0219
0220 rtems_status_code beagle_qep_disable(BBB_PWMSS pwmss_id)
0221 {
0222 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0223 return RTEMS_INVALID_ID;
0224 }
0225 const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
0226
0227 REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) &= ~AM335x_EQEP_QEPCTL_PHEN;
0228
0229 return RTEMS_SUCCESSFUL;
0230 }
0231
0232 rtems_status_code beagle_qep_pinmux_setup(
0233 bbb_qep_pin pin_no,
0234 BBB_PWMSS pwmss_id,
0235 bool pullup_enable
0236 )
0237 {
0238 rtems_status_code result = RTEMS_SUCCESSFUL;
0239 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0240 return RTEMS_INVALID_ID;
0241 }
0242
0243
0244 uint32_t pin_mode = BBB_RXACTIVE;
0245 if ( pullup_enable ) {
0246 pin_mode |= BBB_PU_EN;
0247 }
0248
0249 if(pwmss_id == BBB_PWMSS0) {
0250 if (pin_no == BBB_P9_25_0_STROBE) {
0251 REG(AM335X_PADCONF_BASE + AM335X_CONF_MCASP0_AHCLKX) = pin_mode | BBB_MUXMODE(BBB_P9_25_MUX_QEP);
0252 } else if (pin_no == BBB_P9_27_0B_IN) {
0253 REG(AM335X_PADCONF_BASE + AM335X_CONF_MCASP0_FSR) = pin_mode | BBB_MUXMODE(BBB_P9_27_MUX_QEP);
0254 } else if (pin_no == BBB_P9_41_0_IDX) {
0255 REG(AM335X_PADCONF_BASE + AM335X_CONF_MCASP0_AXR1) = pin_mode | BBB_MUXMODE(BBB_P9_41_MUX_QEP);
0256 } else if (pin_no == BBB_P9_42_0A_IN) {
0257 REG(AM335X_PADCONF_BASE + AM335X_CONF_MCASP0_ACLKR) = pin_mode | BBB_MUXMODE(BBB_P9_42_MUX_QEP);
0258 } else {
0259 result = RTEMS_INTERNAL_ERROR;
0260 }
0261 } else if (pwmss_id == BBB_PWMSS1) {
0262 if (pin_no == BBB_P8_31_1_IDX) {
0263 REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA14) = pin_mode | BBB_MUXMODE(BBB_P8_31_MUX_QEP);
0264 } else if (pin_no == BBB_P8_32_1_STROBE) {
0265 REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA15) = pin_mode | BBB_MUXMODE(BBB_P8_32_MUX_QEP);
0266 } else if (pin_no == BBB_P8_33_1B_IN) {
0267 REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA13) = pin_mode | BBB_MUXMODE(BBB_P8_33_MUX_QEP);
0268 } else if (pin_no == BBB_P8_35_1A_IN) {
0269 REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA12) = pin_mode | BBB_MUXMODE(BBB_P8_35_MUX_QEP);
0270 } else {
0271 result = RTEMS_INTERNAL_ERROR;
0272 }
0273 } else if (pwmss_id == BBB_PWMSS2) {
0274 if (pin_no == BBB_P8_11_2B_IN) {
0275 REG(AM335X_PADCONF_BASE + AM335X_CONF_GPMC_AD13) = pin_mode | BBB_MUXMODE(BBB_P8_11_MUX_QEP);
0276 } else if (pin_no == BBB_P8_12_2A_IN) {
0277 REG(AM335X_PADCONF_BASE + AM335X_CONF_GPMC_AD12) = pin_mode | BBB_MUXMODE(BBB_P8_12_MUX_QEP);
0278 } else if (pin_no == BBB_P8_15_2_STROBE) {
0279 REG(AM335X_PADCONF_BASE + AM335X_CONF_GPMC_AD15) = pin_mode | BBB_MUXMODE(BBB_P8_15_MUX_QEP);
0280 } else if (pin_no == BBB_P8_16_2_IDX) {
0281 REG(AM335X_PADCONF_BASE + AM335X_CONF_GPMC_AD14) = pin_mode | BBB_MUXMODE(BBB_P8_16_MUX_QEP);
0282 } else if (pin_no == BBB_P8_39_2_IDX) {
0283 REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA6) = pin_mode | BBB_MUXMODE(BBB_P8_39_MUX_QEP);
0284 } else if (pin_no == BBB_P8_40_2_STROBE) {
0285 REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA7) = pin_mode | BBB_MUXMODE(BBB_P8_40_MUX_QEP);
0286 } else if (pin_no == BBB_P8_41_2A_IN) {
0287 REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA4) = pin_mode | BBB_MUXMODE(BBB_P8_41_MUX_QEP);
0288 } else if (pin_no == BBB_P8_42_2B_IN) {
0289 REG(AM335X_PADCONF_BASE + AM335X_CONF_LCD_DATA5) = pin_mode | BBB_MUXMODE(BBB_P8_42_MUX_QEP);
0290 } else {
0291 result = RTEMS_INTERNAL_ERROR;
0292 }
0293 } else {
0294 result = RTEMS_INTERNAL_ERROR;
0295 }
0296 return result;
0297 }
0298
0299 int32_t beagle_qep_get_position(BBB_PWMSS pwmss_id)
0300 {
0301 int32_t position = 0;
0302 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0303 return -1;
0304 }
0305 const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
0306
0307 if (eqep->quadrature_mode == ABSOLUTE) {
0308
0309 position = REG(eqep->mmio_base + AM335x_EQEP_QPOSCNT);
0310 } else if (eqep->quadrature_mode == RELATIVE) {
0311
0312 position = REG(eqep->mmio_base + AM335x_EQEP_QPOSLAT);
0313 }
0314
0315 return position;
0316 }
0317
0318 rtems_status_code beagle_qep_set_position(BBB_PWMSS pwmss_id, uint32_t position)
0319 {
0320 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0321 return RTEMS_INVALID_ID;
0322 }
0323 const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
0324
0325 if (eqep->quadrature_mode == ABSOLUTE) {
0326 REG(eqep->mmio_base + AM335x_EQEP_QPOSCNT) = position;
0327 }
0328
0329 return RTEMS_SUCCESSFUL;
0330 }
0331
0332 rtems_status_code beagle_qep_set_count_mode(
0333 BBB_PWMSS pwmss_id,
0334 BBB_QEP_COUNT_MODE mode
0335 )
0336 {
0337 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0338 return RTEMS_INVALID_ID;
0339 }
0340 bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
0341 eqep->count_mode = mode;
0342
0343 return RTEMS_SUCCESSFUL;
0344 }
0345
0346 BBB_QEP_COUNT_MODE beagle_qep_get_count_mode(BBB_PWMSS pwmss_id)
0347 {
0348 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0349 return RTEMS_INVALID_ID;
0350 }
0351 const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
0352
0353 return eqep->count_mode;
0354 }
0355
0356 rtems_status_code beagle_qep_set_quadrature_mode(
0357 BBB_PWMSS pwmss_id,
0358 BBB_QEP_QUADRATURE_MODE mode
0359 )
0360 {
0361 uint16_t qepctl;
0362 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0363 return RTEMS_INVALID_ID;
0364 }
0365 bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
0366
0367 qepctl = REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL);
0368
0369 if (mode == ABSOLUTE) {
0370
0371
0372
0373 qepctl &= ~AM335x_EQEP_QEPCTL_PCRM;
0374
0375 eqep->quadrature_mode = ABSOLUTE;
0376 } else if (mode == RELATIVE) {
0377
0378
0379
0380 qepctl |= AM335x_EQEP_QEPCTL_PCRM;
0381
0382 eqep->quadrature_mode = RELATIVE;
0383 }
0384
0385 REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) = qepctl;
0386
0387 return RTEMS_SUCCESSFUL;
0388 }
0389
0390 BBB_QEP_QUADRATURE_MODE beagle_qep_get_quadrature_mode(BBB_PWMSS pwmss_id)
0391 {
0392 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0393 return -1;
0394 }
0395 const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
0396
0397 return eqep->quadrature_mode;
0398 }
0399
0400
0401
0402 uint32_t beagle_eqep_get_timer_period(BBB_PWMSS pwmss_id)
0403 {
0404 uint64_t period;
0405 uint32_t timer_period;
0406 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0407 return -1;
0408 }
0409 const bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
0410
0411
0412 period = REG(eqep->mmio_base + AM335x_EQEP_QUPRD);
0413 period = period * NANO_SEC_PER_SEC;
0414 timer_period = (uint32_t)(period / SYSCLKOUT);
0415
0416 return timer_period;
0417 }
0418
0419 rtems_status_code beagle_eqep_set_timer_period(
0420 BBB_PWMSS pwmss_id,
0421 uint64_t period,
0422 bbb_eqep_timer_callback timer_callback,
0423 void* user
0424 )
0425 {
0426 uint16_t qepctl;
0427 uint64_t tmp_period;
0428 uint32_t timer_period;
0429 if ( pwmss_id >= BBB_PWMSS_COUNT ) {
0430 return RTEMS_INVALID_ID;
0431 }
0432 bbb_eqep* eqep = &bbb_eqep_table[pwmss_id];
0433
0434
0435 qepctl = readw(eqep->mmio_base + AM335x_EQEP_QEPCTL);
0436 qepctl &= ~(AM335x_EQEP_QEPCTL_UTE | AM335x_EQEP_QEPCTL_QCLM);
0437 REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) = qepctl;
0438
0439
0440 REG(eqep->mmio_base + AM335x_EQEP_QUTMR) = 0;
0441
0442
0443 if (period) {
0444
0445 tmp_period = period * SYSCLKOUT;
0446 timer_period = (uint32_t)(tmp_period / NANO_SEC_PER_SEC);
0447 REG(eqep->mmio_base + AM335x_EQEP_QUPRD) = timer_period;
0448
0449
0450 qepctl |= AM335x_EQEP_QEPCTL_UTE | AM335x_EQEP_QEPCTL_QCLM;
0451 REG16(eqep->mmio_base + AM335x_EQEP_QEPCTL) = qepctl;
0452
0453
0454 if (timer_callback != NULL) {
0455 eqep->timer_callback = timer_callback;
0456 }
0457
0458 if (user != NULL) {
0459 eqep->user = user;
0460 }
0461 }
0462
0463 return RTEMS_SUCCESSFUL;
0464 }