PWM configuration on advantech PCI1760

54 views
Skip to first unread message

Federico Alfatti

unread,
Dec 19, 2022, 10:11:20 AM12/19/22
to Comedi: Linux Control and Measurement Device Interface
Hello everybody, 
I hope that there is someone here that can help me. 

I am trying to generate a PWM signal from the advantech PCI1760 card. I am using Ubuntu 22.04.1 LTS. 
Running the  following code: 

/sbin/modprobe comedi
/sbin/modprobe pci1760
/usr/sbin/comedi_config /dev/comedi0 pci1760

The last command returns that the device is already configured. 

At this point, taking inspiration from the pwm.c file from comedilib demo folder, I am trying to configure the PWM channel via instructions and then sending a comedi_data_write, but it seems to not accept my inputs: the function comedi_do_insn always returns error, no matter what INSN_CONFIG I am using. 

The device is correctely installed because I am able to both read and write on the other two DI/DO subdevices. However, I reckon I might be missing something on the INSN_CONFIG command for the pwm. 
I attach the comedi_board_info results and the code I am running. 
The "max data value" associated with the PWM subdevice 2 is 0, which seems strange to me: for my understanding, this value should represent the maximum resolution for the PWM, which in this specific case should be 2^16 (65535). 

Lastly, I read a "SDF_MODE0: can do mode 0". This should be an indication to the possible counter mode,  UP_COUNTER? Is there something that I am missing or that I am not configuring?

Is there anybody that could help, or that have some specific experience with the PWM control of this board? It would be really useful since I am struggling on this problem, and I am not able to find any documentation that could help me. 

Thank you very much for your time, 
Kind regards, 

Federico 

//////////////////// comedi_board_info -v ////////////////////////

overall info:
  version code: 0x00074c
  driver name: adv_pci1760
  board name: adv_pci1760
  number of subdevices: 4
subdevice 0:
  type: 3 (digital input)
  flags: 0x00010000
          SDF_READABLE:subdevice can be read
  number of channels: 8
  max data value: 1
  ranges:
    all chans: [0 V,5 V]
  command:
    not supported
subdevice 1:
  type: 4 (digital output)
  flags: 0x00020000
          SDF_WRITABLE:subdevice can be written
  number of channels: 8
  max data value: 1
  ranges:
    all chans: [0 V,5 V]
  command:
    not supported
subdevice 2:
  type: 12 (pwm)
  flags: 0x00000080
          SDF_MODE0:can do mode 0
  number of channels: 2
  max data value: 0
  ranges:
    all chans: [0,1]
  command:
    not supported
subdevice 3:
  type: 0 (unused)


//////////////////////////////PROGRAM/////////////////////////////////////////

#include <stdio.h>
#include <comedilib.h>
#define N_SAMPLE 3

char *filename="/dev/comedi0";
comedi_t *device;
int subdevice = 2;
int channel = 0;
int aref;
int range = 0;

int main(int argc, char *argv[])
{
lsampl_t data[N_SAMPLE];

int ret, i;

int n_channels, n_range;

device = comedi_open(filename);
if(!device){
printf("E: comedi_open(\"%s\") NOT SUCCESSFUL",filename);
}

/*Configure PWM*/
comedi_insn insn;

data[0] = INSN_CONFIG_ARM;
data[1] = 0;
   
    insn.subdev = subdevice;
    insn.insn = INSN_CONFIG;
    insn.n = 3;
    insn.chanspec = CR_PACK(channel, range, 0);
    insn.data = data;

ret = comedi_do_insn(device,&insn); //This command is always returning -1
printf("\n\nconfig arm %d\n\n",ret);

/* Activate PWM */
ret = comedi_data_write(device,subdevice,channel,0,0,10); //This command is always returning -1
printf("write %d\n\n",ret);

comedi_close(device);
return 0;
}

Ian Abbott

unread,
Jan 3, 2023, 8:42:51 AM1/3/23
to comed...@googlegroups.com, Federico Alfatti
Sorry for the long delay in replying.

It seems that the PWM subdevice for the PCI1760 needs to be operated
differently to the PWM subdevice on some other devices. On the PCI1760
PWM subdevice, all operations are done using the INSN_CONFIG instruction:

* INSN_CONFIG_PWM_OUTPUT - disables PWM output and sets PWM high and low
periods in nanoseconds:

lsampl_t data[5];
comedi_insn insn;
insn.subdev = 2; // PWM subdevice
insn.insn = INSN_CONFIG;
insn.chanspec = channel; // 0 or 1
insn.n = 5;
insn.data = data;
data[0] = INSN_CONFIG_PWM_OUTPUT;
// set rounding for high period
data[1] = CMDF_ROUND_NEAREST; // or CMDF_ROUND_UP or CMDF_ROUND_DOWN
data[2] = high_ns; // high period in ns
// set rounding for low period
data[3] = CMDF_ROUND_NEAREST; // or CMDF_ROUND_UP or CMDF_ROUND_DOWN
data[4] = low_ns; // low period in ns
ret = comedi_do_insn(device, &insn);

Note: on success, data[2] and data[4] are set to the rounded high and
low periods.

* INSN_CONFIG_ARM - enables PWM output and sets number of cycles or
"continuous":

lsampl_t data[2];
comedi_insn insn;
insn.subdev = 2; // PWM subdevice
insn.insn = INSN_CONFIG;
insn.chanspec = channel; // 0 or 1
insn.n = 2;
insn.data = data;
data[0] = INSN_CONFIG_ARM;
data[1] = 0; // 0 = "continuous", 1 to 65535 = number of cycles
ret = comedi_do_insn(device, &insn);

* INSN_CONFIG_DISARM - disables PWM output:

lsampl_t data[1];
comedi_insn insn;
insn.subdev = 2; // PWM subdevice
insn.insn = INSN_CONFIG;
insn.chanspec = channel; // 0 or 1
insn.n = 1;
insn.data = data;
data[0] = INSN_CONFIG_DISARM;
ret = comedi_do_insn(device, &insn);

* INSN_CONFIG_GET_PWM_OUTPUT - get configured high and low periods:

lsampl_t data[3];
comedi_insn insn;
insn.subdev = 2; // PWM subdevice
insn.insn = INSN_CONFIG;
insn.chanspec = channel; // 0 or 1
insn.n = 3;
insn.data = data;
data[0] = INSN_CONFIG_GET_PWM_OUTPUT;
ret = comedi_do_insn(device, &insn);

On success, the high period is in data[1] and the low period is in
data[2].

* INSN_CONFIG_GET_PWM_STATUS - get PWM status:

lsampl_t data[2];
comedi_insn insn;
insn.subdev = 2; // PWM subdevice
insn.insn = INSN_CONFIG;
insn.chanspec = channel; // 0 or 1
insn.n = 2;
insn.data = data;
data[0] = INSN_CONFIG_GET_PWM_STATUS;
ret = comedi_do_insn(device, &insn);

On success, the enable/disable status in in data[1].


Unfortunately, there seems to be a bug in the driver which probably
stops most of the above instructions from working. The problem is that
the driver is sending wrong command code to read the PWM status
register. In the driver code at
<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/comedi/drivers/adv_pci1760.c?h=v6.1>
the PCI1760_CMD_GET_STATUS macro should be defined as 0x07, not 0x03.
I'll send a patch to the Linux kernel mailing lists to get it fixed, but
it will be some time before it makes its way into the stable kernel
versions.

--
-=( Ian Abbott <abb...@mev.co.uk> || MEV Ltd. is a company )=-
-=( registered in England & Wales. Regd. number: 02862268. )=-
-=( Regd. addr.: S11 & 12 Building 67, Europa Business Park, )=-
-=( Bird Hall Lane, STOCKPORT, SK3 0XA, UK. || www.mev.co.uk )=-

Reply all
Reply to author
Forward
0 new messages