#include <rtapi_slab.h>
#include <rtapi_stdint.h>
#include "rtapi.h"
#include "rtapi_string.h"
#include "rtapi_math.h"
#include "hal.h"
#include "hal/drivers/mesa-hostmot2/hostmot2.h"
void hm2_tp_pwmgen_handle_pwm_frequency(hostmot2_t *hm2) {
rtapi_u32 dds;
int deadtime;
int i;
if (hm2->tp_pwmgen.hal->param.pwm_frequency < 1) {
HM2_ERR("3pwmgen.pwm_frequency %d is too low, setting to 1\n",
hm2->tp_pwmgen.hal->param.pwm_frequency);
hm2->tp_pwmgen.hal->param.pwm_frequency = 1;
}
dds = ((double)hm2->tp_pwmgen.hal->param.pwm_frequency * 65536.0 * 2048.0)
/ (double)hm2->tp_pwmgen.clock_frequency;
if (dds < 65536) {
hm2->tp_pwmgen.pwmgen_master_rate_dds_reg = dds;
} else {
dds = 65535;
hm2->tp_pwmgen.hal->param.pwm_frequency =
((double)hm2->tp_pwmgen.clock_frequency * 65535.0)
/ (65536.0 * 2048.0);
HM2_ERR("max PWM frequency is %d Hz\n",
hm2->tp_pwmgen.hal->param.pwm_frequency);
hm2->tp_pwmgen.pwmgen_master_rate_dds_reg = dds;
}
for (i=0; i < hm2->tp_pwmgen.num_instances; i++) {
if (hm2->tp_pwmgen.instance[i].hal.param.sampletime > 1){
HM2_ERR("Max sampletime is 1 (end of PWM cycle");
hm2->tp_pwmgen.instance[i].hal.param.sampletime = 1;
}
else if (hm2->tp_pwmgen.instance[i].hal.param.sampletime < 0){
HM2_ERR("Min sampletime is 0 (beginning of PWM cycle");
hm2->tp_pwmgen.instance[i].hal.param.sampletime = 0;
}
deadtime = (hm2->tp_pwmgen.instance[i].hal.param.deadzone
* hm2->tp_pwmgen.clock_frequency * dds) / (2 * 65536 * 1e9);
if (deadtime > 511){
deadtime = 511;
hm2->tp_pwmgen.instance[i].hal.param.deadzone =
((double)deadtime * 2.0 * 65536.0 * 1.0e9)
/((double)hm2->tp_pwmgen.clock_frequency * dds);
HM2_ERR("At this PWM frequency the maximum deadtime is %dnS\n",
(int)hm2->tp_pwmgen.instance[i].hal.param.deadzone);
}
else if (deadtime < 0) {
HM2_ERR("Deadtime must be positive");
deadtime = 0;
hm2->tp_pwmgen.instance[i].hal.param.deadzone = 0;
}
hm2->tp_pwmgen.setup_reg[i] = (
((int)(hm2->tp_pwmgen.instance[i].hal.param.sampletime*1023) << 16)
+((hm2->tp_pwmgen.instance[i].hal.param.faultpolarity != 0) << 15)
+(deadtime));
}
}
void hm2_tp_pwmgen_force_write(hostmot2_t *hm2) {
int i;
if (hm2->tp_pwmgen.num_instances == 0) return;
hm2_tp_pwmgen_handle_pwm_frequency(hm2);
for (i = 0; i < hm2->tp_pwmgen.num_instances; i ++) {
if (*hm2->tp_pwmgen.instance[i].hal.pin.enable)
hm2->tp_pwmgen.enable_reg[i] = 1;
else
hm2->tp_pwmgen.enable_reg[i] = 0;
}
hm2->llio->write(hm2->llio, hm2->tp_pwmgen.setup_addr, hm2->tp_pwmgen.setup_reg, (hm2->tp_pwmgen.num_instances * sizeof(rtapi_u32)));
hm2->llio->write(hm2->llio, hm2->tp_pwmgen.enable_addr, hm2->tp_pwmgen.enable_reg, (hm2->tp_pwmgen.num_instances * sizeof(rtapi_u32)));
hm2->llio->write(hm2->llio, hm2->tp_pwmgen.pwmgen_master_rate_dds_addr, &hm2->tp_pwmgen.pwmgen_master_rate_dds_reg, sizeof(rtapi_u32));
if ((*hm2->llio->io_error) != 0) return;
for (i = 0; i < hm2->tp_pwmgen.num_instances; i ++) {
hm2->tp_pwmgen.instance[i].written_faultpolarity = hm2->tp_pwmgen.instance[i].hal.param.faultpolarity;
hm2->tp_pwmgen.instance[i].written_deadzone = hm2->tp_pwmgen.instance[i].hal.param.deadzone;
hm2->tp_pwmgen.instance[i].written_sampletime = hm2->tp_pwmgen.instance[i].hal.param.sampletime;
}
hm2->tp_pwmgen.written_pwm_frequency = hm2->tp_pwmgen.hal->param.pwm_frequency;
}
void hm2_tp_pwmgen_write(hostmot2_t *hm2) {
int i;
if (hm2->tp_pwmgen.num_instances == 0) return;
if (hm2->tp_pwmgen.hal->param.pwm_frequency != hm2->tp_pwmgen.written_pwm_frequency) goto force_write;
for (i = 0; i < hm2->tp_pwmgen.num_instances; i ++) {
if ((hm2->tp_pwmgen.instance[i].hal.param.deadzone != hm2->tp_pwmgen.instance[i].written_deadzone)
|| (hm2->tp_pwmgen.instance[i].hal.param.sampletime != hm2->tp_pwmgen.instance[i].written_sampletime)
|| (hm2->tp_pwmgen.instance[i].hal.param.faultpolarity != hm2->tp_pwmgen.instance[i].written_faultpolarity))
goto force_write;
if ((*hm2->tp_pwmgen.instance[i].hal.pin.enable != (hm2->tp_pwmgen.enable_reg[i] & 1)))
goto force_write;
}
return;
force_write:
hm2_tp_pwmgen_force_write(hm2);
}
void hm2_tp_pwmgen_queue_read(hostmot2_t *hm2) {
hm2->llio->queue_read(hm2->llio, hm2->tp_pwmgen.enable_addr, hm2->tp_pwmgen.enable_reg, (hm2->tp_pwmgen.num_instances * sizeof(rtapi_u32)));
}
void hm2_tp_pwmgen_process_read(hostmot2_t *hm2) {
int i;
for (i = 0 ; i < hm2->tp_pwmgen.num_instances ; i++) {
*hm2->tp_pwmgen.instance[i].hal.pin.fault
= (hm2->tp_pwmgen.enable_reg[i] & 2);
}
}
int hm2_tp_pwmgen_parse_md(hostmot2_t *hm2, int md_index) {
hm2_module_descriptor_t *md = &hm2->md[md_index];
int r;
if (!hm2_md_is_consistent_or_complain(hm2, md_index, 0, 4, 4, 0x0003)) {
HM2_ERR("inconsistent Module Descriptor!\n");
return -EINVAL;
}
if (hm2->tp_pwmgen.num_instances != 0) {
HM2_ERR(
"found duplicate Module Descriptor for %s (inconsistent firmware), not loading driver\n",
hm2_get_general_function_name(md->gtag)
);
return -EINVAL;
}
if (hm2->config.num_tp_pwmgens > md->instances) {
HM2_ERR(
"config.num_3pwmgens=%d, but only %d are available, not loading driver\n",
hm2->config.num_tp_pwmgens,
md->instances
);
return -EINVAL;
}
if (hm2->config.num_tp_pwmgens == 0) {
return 0;
}
if (hm2->config.num_tp_pwmgens == -1) {
hm2->tp_pwmgen.num_instances = md->instances;
} else {
hm2->tp_pwmgen.num_instances = hm2->config.num_tp_pwmgens;
}
hm2->tp_pwmgen.instance = (hm2_tp_pwmgen_instance_t *)hal_malloc(hm2->tp_pwmgen.num_instances * sizeof(hm2_tp_pwmgen_instance_t));
if (hm2->tp_pwmgen.instance == NULL) {
HM2_ERR("out of memory!\n");
r = -ENOMEM;
goto fail0;
}
hm2->tp_pwmgen.hal = (hm2_tp_pwmgen_global_hal_t *)hal_malloc(sizeof(hm2_tp_pwmgen_global_hal_t));
if (hm2->tp_pwmgen.instance == NULL) {
HM2_ERR("out of memory!\n");
r = -ENOMEM;
goto fail0;
}
hm2->tp_pwmgen.clock_frequency = md->clock_freq;
hm2->tp_pwmgen.version = md->version;
hm2->tp_pwmgen.pwm_value_addr = md->base_address + (0 * md->register_stride);
hm2->tp_pwmgen.pwmgen_master_rate_dds_addr = md->base_address + (3 * md->register_stride);
hm2->tp_pwmgen.enable_addr = md->base_address + (1 * md->register_stride);
hm2->tp_pwmgen.setup_addr = md->base_address + (2 * md->register_stride);
hm2->tp_pwmgen.setup_reg = (rtapi_u32 *)rtapi_kmalloc(hm2->tp_pwmgen.num_instances * sizeof(rtapi_u32), RTAPI_GFP_KERNEL);
if (hm2->tp_pwmgen.setup_reg == NULL) {
HM2_ERR("out of memory!\n");
r = -ENOMEM;
goto fail1;
}
hm2->tp_pwmgen.enable_reg = (rtapi_u32 *)rtapi_kmalloc(hm2->tp_pwmgen.num_instances * sizeof(rtapi_u32), RTAPI_GFP_KERNEL);
if (hm2->tp_pwmgen.enable_reg == NULL) {
HM2_ERR("out of memory!\n");
r = -ENOMEM;
goto fail2;
}
r = hm2_register_tram_write_region(hm2, hm2->tp_pwmgen.pwm_value_addr, (hm2->tp_pwmgen.num_instances * sizeof(rtapi_u32)), &hm2->tp_pwmgen.pwm_value_reg);
if (r < 0) {
HM2_ERR("error registering tram write region for 3PWM Value register (%d)\n", r);
goto fail2;
}
{
int i;
int r;
char name[HAL_NAME_LEN + 1];
r = hal_param_u32_newf(
HAL_RW,
&(hm2->tp_pwmgen.hal->param.pwm_frequency),
hm2->llio->comp_id,
"%s.3pwmgen.frequency",
hm2->llio->name
);
if (r < 0) {
HM2_ERR("error adding pin 3pwmgen.frequency param, aborting\n");
goto fail2;
}
hm2->tp_pwmgen.hal->param.pwm_frequency = 20000;
hm2->tp_pwmgen.written_pwm_frequency = 0;
for (i = 0; i < hm2->tp_pwmgen.num_instances; i ++) {
rtapi_snprintf(name, sizeof(name), "%s.3pwmgen.%02d.A-value", hm2->llio->name, i);
r = hal_pin_float_new(name, HAL_IN, &(hm2->tp_pwmgen.instance[i].hal.pin.Avalue), hm2->llio->comp_id);
if (r < 0) {
HM2_ERR("error adding pin '%s', aborting\n", name);
goto fail2;
}
rtapi_snprintf(name, sizeof(name), "%s.3pwmgen.%02d.B-value", hm2->llio->name, i);
r = hal_pin_float_new(name, HAL_IN, &(hm2->tp_pwmgen.instance[i].hal.pin.Bvalue), hm2->llio->comp_id);
if (r < 0) {
HM2_ERR("error adding pin '%s', aborting\n", name);
goto fail2;
}
rtapi_snprintf(name, sizeof(name), "%s.3pwmgen.%02d.C-value", hm2->llio->name, i);
r = hal_pin_float_new(name, HAL_IN, &(hm2->tp_pwmgen.instance[i].hal.pin.Cvalue), hm2->llio->comp_id);
if (r < 0) {
HM2_ERR("error adding pin '%s', aborting\n", name);
goto fail2;
}
rtapi_snprintf(name, sizeof(name), "%s.3pwmgen.%02d.enable", hm2->llio->name, i);
r = hal_pin_bit_new(name, HAL_IN, &(hm2->tp_pwmgen.instance[i].hal.pin.enable), hm2->llio->comp_id);
if (r < 0) {
HM2_ERR("error adding pin '%s', aborting\n", name);
goto fail2;
}
rtapi_snprintf(name, sizeof(name), "%s.3pwmgen.%02d.fault", hm2->llio->name, i);
r = hal_pin_bit_new(name, HAL_OUT, &(hm2->tp_pwmgen.instance[i].hal.pin.fault), hm2->llio->comp_id);
if (r < 0) {
HM2_ERR("error adding pin '%s', aborting\n", name);
goto fail2;
}
rtapi_snprintf(name, sizeof(name), "%s.3pwmgen.%02d.scale", hm2->llio->name, i);
r = hal_param_float_new(name, HAL_RW, &(hm2->tp_pwmgen.instance[i].hal.param.scale), hm2->llio->comp_id);
if (r < 0) {
HM2_ERR("error adding param '%s', aborting\n", name);
goto fail2;
}
rtapi_snprintf(name, sizeof(name), "%s.3pwmgen.%02d.deadtime", hm2->llio->name, i);
r = hal_param_float_new(name, HAL_RW, &(hm2->tp_pwmgen.instance[i].hal.param.deadzone), hm2->llio->comp_id);
if (r < 0) {
HM2_ERR("error adding param '%s', aborting\n", name);
goto fail2;
}
rtapi_snprintf(name, sizeof(name), "%s.3pwmgen.%02d.fault-invert", hm2->llio->name, i);
r = hal_param_bit_new(name, HAL_RW, &(hm2->tp_pwmgen.instance[i].hal.param.faultpolarity), hm2->llio->comp_id);
if (r < 0) {
HM2_ERR("error adding param '%s', aborting\n", name);
goto fail2;
}
rtapi_snprintf(name, sizeof(name), "%s.3pwmgen.%02d.sample-time", hm2->llio->name, i);
r = hal_param_float_new(name, HAL_RW, &(hm2->tp_pwmgen.instance[i].hal.param.sampletime), hm2->llio->comp_id);
if (r < 0) {
HM2_ERR("error adding param '%s', aborting\n", name);
goto fail2;
}
*(hm2->tp_pwmgen.instance[i].hal.pin.enable) = 0;
*(hm2->tp_pwmgen.instance[i].hal.pin.Avalue) = 0.0;
*(hm2->tp_pwmgen.instance[i].hal.pin.Bvalue) = 0.0;
*(hm2->tp_pwmgen.instance[i].hal.pin.Cvalue) = 0.0;
hm2->tp_pwmgen.instance[i].hal.param.scale = 1.0;
hm2->tp_pwmgen.instance[i].hal.param.sampletime = 0.5;
hm2->tp_pwmgen.instance[i].hal.param.faultpolarity = 0.0; hm2->tp_pwmgen.instance[i].hal.param.deadzone = 5000;
hm2->tp_pwmgen.instance[i].written_sampletime = -666; }
}
return hm2->tp_pwmgen.num_instances;
fail2:
rtapi_kfree(hm2->tp_pwmgen.enable_reg);
fail1:
rtapi_kfree(hm2->tp_pwmgen.setup_reg);
fail0:
hm2->tp_pwmgen.num_instances = 0;
return r;
}
void hm2_tp_pwmgen_print_module(hostmot2_t *hm2) {
int i;
if (hm2->tp_pwmgen.num_instances <= 0) return;
HM2_PRINT("3-phase PWMGen: %d\n", hm2->tp_pwmgen.num_instances);
HM2_PRINT(" clock_frequency: %d Hz (%s MHz)\n", hm2->tp_pwmgen.clock_frequency, hm2_hz_to_mhz(hm2->tp_pwmgen.clock_frequency));
HM2_PRINT(" version: %d\n", hm2->tp_pwmgen.version);
HM2_PRINT(" pwmgen_master_rate_dds: 0x%08X (%d)\n", hm2->tp_pwmgen.pwmgen_master_rate_dds_reg, hm2->tp_pwmgen.pwmgen_master_rate_dds_reg);
HM2_PRINT(" pwmgen_master_rate_dds_addr: 0x%04X\n", hm2->tp_pwmgen.pwmgen_master_rate_dds_addr);
for (i = 0; i < hm2->tp_pwmgen.num_instances; i ++) {
HM2_PRINT(" instance %d:\n", i);
HM2_PRINT(" hw:\n");
HM2_PRINT(" pwm_value_addr: 0x%04X\n", hm2->tp_pwmgen.pwm_value_addr);
HM2_PRINT(" pwm_val:0x%08X\n", hm2->tp_pwmgen.pwm_value_reg[i]);
HM2_PRINT(" enable: 0x%08X\n", hm2->tp_pwmgen.enable_reg[i]);
HM2_PRINT(" setup: 0x%08X\n", hm2->tp_pwmgen.setup_reg[i]);
}
}
void hm2_tp_pwmgen_prepare_tram_write(hostmot2_t *hm2) {
int i;
if (hm2->tp_pwmgen.num_instances <= 0) return;
for (i = 0; i < hm2->tp_pwmgen.num_instances; i ++) {
double scaled_Avalue;
double scaled_Bvalue;
double scaled_Cvalue;
if (hm2->tp_pwmgen.instance[i].hal.param.scale ==0) {
hm2->tp_pwmgen.instance[i].hal.param.scale = 1;
HM2_ERR("3pwmgen scale must be greater than zero. Scale set to %i", (int)hm2->tp_pwmgen.instance[i].hal.param.scale);
}
scaled_Avalue = (*hm2->tp_pwmgen.instance[i].hal.pin.Avalue / hm2->tp_pwmgen.instance[i].hal.param.scale);
scaled_Bvalue = (*hm2->tp_pwmgen.instance[i].hal.pin.Bvalue / hm2->tp_pwmgen.instance[i].hal.param.scale);
scaled_Cvalue = (*hm2->tp_pwmgen.instance[i].hal.pin.Cvalue / hm2->tp_pwmgen.instance[i].hal.param.scale);
if (scaled_Avalue > 1.0) scaled_Avalue = 1.0;
else if (scaled_Avalue < -1.0) scaled_Avalue = -1.0;
if (scaled_Bvalue > 1.0) scaled_Bvalue = 1.0;
else if (scaled_Avalue < -1.0) scaled_Avalue = -1.0;
if (scaled_Cvalue > 1.0) scaled_Cvalue = 1.0;
else if (scaled_Avalue < -1.0) scaled_Avalue = -1.0;
hm2->tp_pwmgen.pwm_value_reg[i] = (
((long)(scaled_Cvalue * (511.0) + 512.0) << 20)
+ ((long)(scaled_Bvalue * (511.0) + 512.0) << 10)
+ ((long)(scaled_Avalue * (511.0) + 512.0) << 0)
);
}
}
void hm2_tp_pwmgen_cleanup(hostmot2_t *hm2) {
if (hm2->tp_pwmgen.num_instances <= 0) return;
if (hm2->tp_pwmgen.setup_reg != NULL) {
rtapi_kfree(hm2->tp_pwmgen.setup_reg);
hm2->tp_pwmgen.enable_reg = NULL;
}
if (hm2->tp_pwmgen.enable_reg != NULL) {
rtapi_kfree(hm2->tp_pwmgen.enable_reg);
hm2->tp_pwmgen.enable_reg = NULL;
}
hm2->tp_pwmgen.num_instances = 0;
}