00001
00047 #include "dc_motor.h"
00048 #include "hw/hw_dc_motor.h"
00049
00050
00051 #define LOG_LEVEL DC_MOTOR_LOG_LEVEL
00052 #define LOG_FORMAT DC_MOTOR_LOG_FORMAT
00053
00054 #include <cfg/log.h>
00055 #include <cfg/debug.h>
00056
00057 #include <algo/pid_control.h>
00058
00059 #include <drv/timer.h>
00060
00061 #include <kern/proc.h>
00062
00063 #include <cpu/power.h>
00064
00065 #include <string.h>
00066
00070 #define DC_MOTOR_ACTIVE BV(0) ///< DC motor enable or disable flag.
00071 #define DC_MOTOR_DIR BV(1) ///< Spin direction of DC motor.
00072
00073
00074
00075
00076 #define POS_DIR 1
00077 #define NEG_DIR 0
00078 #define DC_MOTOR_POS_DIR(x) ((x) |= DC_MOTOR_DIR) // Set directions status positive
00079 #define DC_MOTOR_NEG_DIR(x) ((x) &= ~DC_MOTOR_DIR) // Set directions status negative
00080
00081
00082 #define DC_MOTOR_SET_STATUS_DIR(status, dir) \
00083 (dir == POS_DIR ? DC_MOTOR_POS_DIR(status) : DC_MOTOR_NEG_DIR(status))
00084
00085 #if (CONFIG_KERN && CONFIG_KERN_PREEMPT)
00086 #if CONFIG_DC_MOTOR_USE_SEM
00087 #include <kern/sem.h>
00088
00089 Semaphore dc_motor_sem;
00090 #define DC_MOTOR_LOCK sem_obtain(&dc_motor_sem)
00091 #define DC_MOTOR_UNLOCK sem_release(&dc_motor_sem)
00092 #else
00093 #define DC_MOTOR_LOCK proc_forbid()
00094 #define DC_MOTOR_UNLOCK proc_permit()
00095 #endif
00096 #else
00097 #define DC_MOTOR_LOCK
00098 #define DC_MOTOR_UNLOCK
00099 #endif
00100
00104 static DCMotor dcm_all[CONFIG_NUM_DC_MOTOR];
00105
00106
00107
00108
00109 struct Process *dc_motor;
00110
00111
00112
00113 static PROC_DEFINE_STACK(dc_motor_poll_stack, 500);
00114
00115
00116 LOG_INFOB(static int debug_msg_delay = 0;);
00117
00118
00119 INLINE dc_speed_t dc_motor_readSpeed(int index)
00120 {
00121 DCMotor *dcm = &dcm_all[index];
00122 return HW_DC_MOTOR_READ_VALUE(dcm->cfg->adc_ch, dcm->cfg->adc_min, dcm->cfg->adc_max);
00123 }
00124
00128 dc_speed_t dc_motor_readTargetSpeed(int index)
00129 {
00130 DCMotor *dcm = &dcm_all[index];
00131 return HW_DC_MOTOR_READ_VALUE(dcm->cfg->speed_dev_id, CONFIG_DC_MOTOR_MIN_SPEED, CONFIG_DC_MOTOR_MAX_SPEED);
00132 }
00133
00134 static void dc_motor_start(int index)
00135 {
00136 DCMotor *dcm = &dcm_all[index];
00137
00138 DC_MOTOR_LOCK;
00139
00140
00141
00142
00143 pid_control_reset(&dcm->pid_ctx);
00144 dcm->status |= DC_MOTOR_ACTIVE;
00145 DC_MOTOR_UNLOCK;
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 static void dc_motor_stop(int index)
00160 {
00161 DCMotor *dcm = &dcm_all[index];
00162
00163 DC_MOTOR_LOCK;
00164
00165 dcm->status &= ~DC_MOTOR_ACTIVE;
00166 dcm->expire_time = DC_MOTOR_NO_EXPIRE;
00167 pwm_enable(dcm->cfg->pwm_dev, false);
00168
00169 if (dcm->cfg->braked)
00170 {
00171 DC_MOTOR_STOP_BRAKED(dcm->index);
00172 }
00173 else
00174 {
00175 DC_MOTOR_STOP_FLOAT(dcm->index);
00176 }
00177
00178 DC_MOTOR_UNLOCK;
00179 }
00180
00181
00182
00183
00184
00185 static void dc_motor_do(int index)
00186 {
00187 DCMotor *dcm = &dcm_all[index];
00188
00189 dc_speed_t curr_pos = 0;
00190 pwm_duty_t new_pid = 0;
00191
00192 DC_MOTOR_LOCK;
00193
00194
00195 if (!(dcm->status & DC_MOTOR_ACTIVE))
00196 {
00197 DC_MOTOR_UNLOCK;
00198 return;
00199 }
00200
00201
00202
00203
00204
00205 pwm_setPolarity(dcm->cfg->pwm_dev, dcm->status & DC_MOTOR_DIR);
00206 DC_MOTOR_SET_DIR(dcm->index, dcm->status & DC_MOTOR_DIR);
00207
00208
00209 if (dcm->cfg->pid_enable)
00210 {
00211
00212
00213
00214
00215
00216
00217 DC_MOTOR_UNLOCK;
00218 curr_pos = dc_motor_readSpeed(index);
00219 DC_MOTOR_LOCK;
00220 new_pid = pid_control_update(&dcm->pid_ctx, dcm->tgt_speed, curr_pos);
00221 }
00222 else
00223 {
00224 new_pid = dcm->tgt_speed;
00225 }
00226
00227 LOG_INFOB(
00228 if (debug_msg_delay == 20)
00229 {
00230 LOG_INFO("DC Motor[%d]: curr_speed[%d],curr_pos[%d],tgt[%d]\n", dcm->index,
00231 curr_pos, new_pid, dcm->tgt_speed);
00232 debug_msg_delay = 0;
00233 }
00234 debug_msg_delay++;
00235 );
00236
00237
00238 pwm_setDuty(dcm->cfg->pwm_dev, new_pid);
00239
00240
00241 pwm_enable(dcm->cfg->pwm_dev, true);
00242
00243 DC_MOTOR_ENABLE(dcm->index);
00244 DC_MOTOR_UNLOCK;
00245 }
00246
00247
00248
00249
00250
00251
00252 INLINE bool check_timerIsExpired(int index)
00253 {
00254
00255 DC_MOTOR_LOCK;
00256 bool check = ((dcm_all[index].expire_time - timer_clock()) < 0) &&
00257 (dcm_all[index].expire_time != DC_MOTOR_NO_EXPIRE);
00258 DC_MOTOR_UNLOCK;
00259
00260 return check;
00261 }
00262
00276 static void NORETURN dc_motor_poll(void)
00277 {
00278 for (;;)
00279 {
00280
00281
00282
00283
00284 for (int i = 0; i < CONFIG_NUM_DC_MOTOR; i++)
00285 {
00286 if (!dcm_all[i].cfg)
00287 continue;
00288
00289 if (check_timerIsExpired(i))
00290 dc_motor_stop(i);
00291 else
00292 dc_motor_do(i);
00293
00294
00295
00296
00297
00298
00299 if (dcm_all[i].cfg->speed_dev_id != DC_MOTOR_NO_DEV_SPEED)
00300 dc_motor_setSpeed(i, dc_motor_readTargetSpeed(i));
00301 }
00302
00303
00304 timer_delay(CONFIG_DC_MOTOR_SAMPLE_PERIOD - CONFIG_DC_MOTOR_SAMPLE_DELAY);
00305
00306 for (int i = 0; i < CONFIG_NUM_DC_MOTOR; i++)
00307 {
00308 if (!dcm_all[i].cfg)
00309 continue;
00310
00311 if (check_timerIsExpired(i))
00312 dc_motor_stop(i);
00313
00314 DC_MOTOR_LOCK;
00315 if (dcm_all[i].status & DC_MOTOR_ACTIVE)
00316 {
00317 DC_MOTOR_DISABLE(dcm_all[i].index);
00318 pwm_enable(dcm_all[i].cfg->pwm_dev, false);
00319 }
00320 DC_MOTOR_UNLOCK;
00321 }
00322
00323
00324 timer_delay(CONFIG_DC_MOTOR_SAMPLE_DELAY);
00325 }
00326 }
00327
00334 void dc_motor_setDir(int index, bool dir)
00335 {
00336 DCMotor *dcm = &dcm_all[index];
00337 DC_MOTOR_LOCK;
00338 DC_MOTOR_SET_STATUS_DIR(dcm->status, dir);
00339 DC_MOTOR_UNLOCK;
00340 }
00341
00345 void dc_motor_setSpeed(int index, dc_speed_t speed)
00346 {
00347 DCMotor *dcm = &dcm_all[index];
00348
00349 DC_MOTOR_LOCK;
00350 dcm->tgt_speed = speed;
00351 DC_MOTOR_UNLOCK;
00352
00353 LOG_INFO("DC Motor[%d]: tgt_speed[%d]\n", index, dcm->tgt_speed);
00354 }
00355
00359 void dc_motor_startTimer(int index, mtime_t on_time)
00360 {
00361 DC_MOTOR_LOCK;
00362 dcm_all[index].expire_time = DC_MOTOR_NO_EXPIRE;
00363 if (on_time != DC_MOTOR_NO_EXPIRE)
00364 {
00365 dcm_all[index].expire_time = timer_clock() + ms_to_ticks(on_time);
00366 dc_motor_start(index);
00367 }
00368 DC_MOTOR_UNLOCK;
00369 }
00370
00371 void dc_motor_waitStop(int index)
00372 {
00373 DCMotor *dcm = &dcm_all[index];
00374 bool loop = true;
00375
00376 while (loop)
00377 {
00378 DC_MOTOR_LOCK;
00379 loop = dcm->status & DC_MOTOR_ACTIVE;
00380 DC_MOTOR_UNLOCK;
00381
00382 cpu_relax();
00383 }
00384 }
00385
00389 void dc_motor_enable(int index, bool state)
00390 {
00391 if (state)
00392 dc_motor_start(index);
00393 else
00394 dc_motor_stop(index);
00395 }
00396
00400 void dc_motor_setup(int index, DCMotorConfig *dcm_conf)
00401 {
00402 DCMotor *dcm = &dcm_all[index];
00403
00404 DC_MOTOR_LOCK;
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 pid_control_setPeriod(&dcm_conf->pid_cfg, CONFIG_DC_MOTOR_SAMPLE_PERIOD);
00417
00418
00419 pid_control_init(&dcm->pid_ctx, &dcm_conf->pid_cfg);
00420
00421
00422 dcm->cfg = dcm_conf;
00423
00424
00425
00426
00427 dcm->index = index;
00428
00429
00430
00431
00432 dcm->expire_time = DC_MOTOR_NO_EXPIRE;
00433
00434
00435
00436
00437 dcm->tgt_speed = dcm_conf->speed;
00438
00439
00440
00441
00442 dcm->status = 0;
00443
00444 pwm_setFrequency(dcm->cfg->pwm_dev, dcm->cfg->freq);
00445 pwm_enable(dcm->cfg->pwm_dev, false);
00446
00447
00448 DC_MOTOR_SET_DIR(dcm->index, dcm->cfg->dir);
00449 DC_MOTOR_SET_STATUS_DIR(dcm->status, dcm->cfg->dir);
00450
00451 DC_MOTOR_UNLOCK;
00452
00453 LOG_INFO("DC motor[%d]:\n", dcm->index);
00454 LOG_INFO("> PID: kp[%f],ki[%f],kd[%f]\n", dcm->cfg->pid_cfg.kp, dcm->cfg->pid_cfg.ki, dcm->cfg->pid_cfg.kd);
00455 LOG_INFO("> PWM: pwm_dev[%d], freq[%ld], sample[%d]\n", dcm->cfg->pwm_dev, dcm->cfg->freq,CONFIG_DC_MOTOR_SAMPLE_DELAY);
00456 LOG_INFO("> ADC: adc_ch[%d], adc_max[%d], adc_min[%d]\n", dcm->cfg->adc_ch, dcm->cfg->adc_max, dcm->cfg->adc_min);
00457 LOG_INFO("> DC: dir[%d], speed[%d]\n", dcm->cfg->dir, dcm->cfg->speed);
00458 }
00459
00464 void dc_motor_setPriority(int priority)
00465 {
00466 ASSERT(CONFIG_KERN);
00467 ASSERT(dc_motor);
00468 proc_setPri(dc_motor, priority);
00469 }
00470
00475 void dc_motor_init(void)
00476 {
00477 ASSERT(CONFIG_KERN);
00478
00479 MOTOR_DC_INIT();
00480
00481 #if (CONFIG_KERN_PREEMPT && CONFIG_DC_MOTOR_USE_SEM)
00482 sem_init(&dc_motor_sem);
00483 #endif
00484
00485
00486 dc_motor = proc_new_with_name("DC_Motor", dc_motor_poll, NULL, sizeof(dc_motor_poll_stack), dc_motor_poll_stack);
00487 }
00488