123 lines
3.0 KiB
C++
123 lines
3.0 KiB
C++
/*
|
|
* pwm.h
|
|
*
|
|
* Created on: 29.07.2018
|
|
* Author: eyck
|
|
*/
|
|
|
|
#ifndef PWM_H_
|
|
#define PWM_H_
|
|
|
|
#include <sifive/devices/pwm.h>
|
|
#include "util/bit_field.h"
|
|
#include <limits>
|
|
#include <cstdint>
|
|
|
|
template<uint32_t BASE_ADDR>
|
|
class pwm_regs {
|
|
public:
|
|
BEGIN_BF_DECL(pwmcfg_t, uint32_t);
|
|
BF_FIELD(scale, 0, 4);
|
|
BF_FIELD(sticky, 8, 1);
|
|
BF_FIELD(zerocmp, 9, 1);
|
|
BF_FIELD(deglitch, 10, 1);
|
|
BF_FIELD(enalways, 12, 1);
|
|
BF_FIELD(enoneshot, 13, 1);
|
|
BF_FIELD(cmp0center, 16, 1);
|
|
BF_FIELD(cmp1center, 17, 1);
|
|
BF_FIELD(cmp2center, 18, 1);
|
|
BF_FIELD(cmp3center, 19, 1);
|
|
BF_FIELD(cmp0gang, 24, 1);
|
|
BF_FIELD(cmp1gang, 25, 1);
|
|
BF_FIELD(cmp2gang, 26, 1);
|
|
BF_FIELD(cmp3gang, 27, 1);
|
|
BF_FIELD(cmp0ip, 28, 1);
|
|
BF_FIELD(cmp1ip, 29, 1);
|
|
BF_FIELD(cmp2ip, 30, 1);
|
|
BF_FIELD(cmp3ip, 31, 1);
|
|
END_BF_DECL();
|
|
|
|
BEGIN_BF_DECL(pwms_t, uint32_t);
|
|
BF_FIELD(s, 0, 16);
|
|
END_BF_DECL() r_pwms;
|
|
|
|
BEGIN_BF_DECL(pwmcmp0_t, uint32_t);
|
|
BF_FIELD(cmp0, 0, 16);
|
|
END_BF_DECL() r_pwmcmp0;
|
|
|
|
BEGIN_BF_DECL(pwmcmp1_t, uint32_t);
|
|
BF_FIELD(cmp0, 0, 16);
|
|
END_BF_DECL() r_pwmcmp1;
|
|
|
|
BEGIN_BF_DECL(pwmcmp2_t, uint32_t);
|
|
BF_FIELD(cmp0, 0, 16);
|
|
END_BF_DECL() r_pwmcmp2;
|
|
|
|
BEGIN_BF_DECL(pwmcmp3_t, uint32_t);
|
|
BF_FIELD(cmp0, 0, 16);
|
|
END_BF_DECL() r_pwmcmp3;
|
|
|
|
static inline pwmcfg_t& cfg_reg(){
|
|
return *reinterpret_cast<pwmcfg_t*>(BASE_ADDR+PWM_CFG);
|
|
}
|
|
|
|
static inline uint32_t& count_reg(){
|
|
return *reinterpret_cast<uint32_t*>(BASE_ADDR+PWM_COUNT);
|
|
}
|
|
|
|
static inline pwms_t& s_reg(){
|
|
return *reinterpret_cast<pwms_t*>(BASE_ADDR+PWM_S);
|
|
}
|
|
|
|
static inline pwmcmp0_t& cmp0_reg(){
|
|
return *reinterpret_cast<pwmcmp0_t*>(BASE_ADDR+PWM_CMP0);
|
|
}
|
|
|
|
static inline pwmcmp1_t& cmp1_reg(){
|
|
return *reinterpret_cast<pwmcmp1_t*>(BASE_ADDR+PWM_CMP1);
|
|
}
|
|
|
|
static inline pwmcmp2_t& cmp2_reg(){
|
|
return *reinterpret_cast<pwmcmp2_t*>(BASE_ADDR+PWM_CMP2);
|
|
}
|
|
|
|
static inline pwmcmp3_t& cmp3_reg(){
|
|
return *reinterpret_cast<pwmcmp3_t*>(BASE_ADDR+PWM_CMP3);
|
|
}
|
|
|
|
static inline bool oneshot_delay(long delay_us){
|
|
auto scaling_factor=0;
|
|
while(delay_us/(1<<scaling_factor) > std::numeric_limits<unsigned short>::max()){
|
|
scaling_factor++;
|
|
}
|
|
cfg_reg()=0;
|
|
count_reg()=0;
|
|
cfg_reg().scale=4+scaling_factor; // divide by 16 so we get 1us per pwm clock
|
|
cmp0_reg().cmp0 = delay_us/(1<<scaling_factor);
|
|
pwm_active=true;
|
|
cfg_reg().enoneshot=true;
|
|
do{
|
|
asm("wfi");
|
|
asm("nop");
|
|
}while(pwm_active);
|
|
return true;
|
|
}
|
|
|
|
static void pwm_interrupt_handler(){
|
|
cfg_reg().cmp0ip=false;
|
|
pwm_active=false;
|
|
}
|
|
|
|
inline
|
|
static bool is_active(){ return pwm_active; }
|
|
|
|
inline
|
|
static void set_active() {pwm_active=true;}
|
|
|
|
private:
|
|
static volatile bool pwm_active;
|
|
};
|
|
|
|
|
|
#endif /* PWM_H_ */
|