Re: [comedi] PWM configuration on advantech PCI1760

Ian Abbott <[email protected]> Tue, 3 Jan 2023 13:42:48 +0000
Newsgroups gmane.linux.comedi
Organization MEV Ltd.
Message-ID <[email protected]>
On 19/12/2022 15:11, Federico Alfatti wrote:
> Hello everybody,
> I hope that there is someone here that can help me.
>=20
> I am trying to generate a PWM signal from the advantech PCI1760 card. I=
=20
> am using Ubuntu 22.04.1 LTS.
> Running the=C2=A0 following code:
>=20
> /sbin/modprobe comedi
> /sbin/modprobe pci1760
> /usr/sbin/comedi_config /dev/comedi0 pci1760
>=20
> The last command returns that the device is already configured.
>=20
> At this point, taking inspiration from the pwm.c file from comedilib=20
> demo folder, I am trying to configure the PWM channel via instructions=20
> and then sending a comedi_data_write, but it seems to not accept my=20
> inputs: the function comedi_do_insn always returns error, no matter what=
=20
> INSN_CONFIG I am using.
>=20
> The device is correctely installed because I am able to both read and=20
> write on the other two DI/DO subdevices. However, I reckon I might be=20
> 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=20
> seems strange to me: for my understanding, this value should represent=20
> the maximum resolution for the PWM, which in this specific case should=20
> be 2^16 (65535).
>=20
> Lastly, I read a "SDF_MODE0: can do mode 0". This should be an=20
> indication to the possible counter mode,=C2=A0 UP_COUNTER? Is there somet=
hing=20
> that I am missing or that I am not configuring?
>=20
> Is there anybody that could help, or that have some specific experience=
=20
> with the PWM control of this board? It would be really useful since I am=
=20
> struggling on this problem, and I am not able to find any documentation=
=20
> that could help me.
>=20
> Thank you very much for your time,
> Kind regards,
>=20
> Federico
>=20
> //////////////////// comedi_board_info -v ////////////////////////
>=20
> overall info:
>  =C2=A0 version code: 0x00074c
>  =C2=A0 driver name: adv_pci1760
>  =C2=A0 board name: adv_pci1760
>  =C2=A0 number of subdevices: 4
> subdevice 0:
>  =C2=A0 type: 3 (digital input)
>  =C2=A0 flags: 0x00010000
>  =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDF_READABLE:subdevice can be read
>  =C2=A0 number of channels: 8
>  =C2=A0 max data value: 1
>  =C2=A0 ranges:
>  =C2=A0 =C2=A0 all chans: [0 V,5 V]
>  =C2=A0 command:
>  =C2=A0 =C2=A0 not supported
> subdevice 1:
>  =C2=A0 type: 4 (digital output)
>  =C2=A0 flags: 0x00020000
>  =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDF_WRITABLE:subdevice can be written
>  =C2=A0 number of channels: 8
>  =C2=A0 max data value: 1
>  =C2=A0 ranges:
>  =C2=A0 =C2=A0 all chans: [0 V,5 V]
>  =C2=A0 command:
>  =C2=A0 =C2=A0 not supported
> subdevice 2:
>  =C2=A0 type: 12 (pwm)
>  =C2=A0 flags: 0x00000080
>  =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 SDF_MODE0:can do mode 0
>  =C2=A0 number of channels: 2
>  =C2=A0 max data value: 0
>  =C2=A0 ranges:
>  =C2=A0 =C2=A0 all chans: [0,1]
>  =C2=A0 command:
>  =C2=A0 =C2=A0 not supported
> subdevice 3:
>  =C2=A0 type: 0 (unused)
>=20
>=20
> //////////////////////////////PROGRAM////////////////////////////////////=
/////
>=20
> #include <stdio.h>
> #include <comedilib.h>
> #define N_SAMPLE 3
>=20
> char *filename=3D"/dev/comedi0";
> comedi_t *device;
> int subdevice =3D 2;
> int channel =3D 0;
> int aref;
> int range =3D 0;
>=20
> int main(int argc, char *argv[])
> {
> lsampl_t data[N_SAMPLE];
>=20
> int ret, i;
>=20
> int n_channels, n_range;
>=20
> device =3D comedi_open(filename);
> if(!device){
> printf("E: comedi_open(\"%s\") NOT SUCCESSFUL",filename);
> }
>=20
> /*Configure PWM*/
> comedi_insn insn;
>=20
> data[0] =3D INSN_CONFIG_ARM;
> data[1] =3D 0;
>  =C2=A0 =C2=A0 insn.subdev =3D subdevice;
>  =C2=A0 =C2=A0 insn.insn =3D INSN_CONFIG;
>  =C2=A0 =C2=A0 insn.n =3D 3;
>  =C2=A0 =C2=A0 insn.chanspec =3D CR_PACK(channel, range, 0);
>  =C2=A0 =C2=A0 insn.data =3D data;
>=20
> ret =3D comedi_do_insn(device,&insn); //This command is always returning =
-1
> printf("\n\nconfig arm %d\n\n",ret);
>=20
> /* Activate PWM */
> ret =3D comedi_data_write(device,subdevice,channel,0,0,10); //This comman=
d=20
> is always returning -1
> printf("write %d\n\n",ret);
>=20
> comedi_close(device);
> return 0;
> }

Sorry for the long delay in replying.

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

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

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

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

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

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

* INSN_CONFIG_DISARM - disables PWM output:

     lsampl_t data[1];
     comedi_insn insn;
     insn.subdev =3D 2; // PWM subdevice
     insn.insn =3D INSN_CONFIG;
     insn.chanspec =3D channel; // 0 or 1
     insn.n =3D 1;
     insn.data =3D data;
     data[0] =3D INSN_CONFIG_DISARM;
     ret =3D 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 =3D 2; // PWM subdevice
     insn.insn =3D INSN_CONFIG;
     insn.chanspec =3D channel; // 0 or 1
     insn.n =3D 3;
     insn.data =3D data;
     data[0] =3D INSN_CONFIG_GET_PWM_OUTPUT;
     ret =3D comedi_do_insn(device, &insn);

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

* INSN_CONFIG_GET_PWM_STATUS - get PWM status:

     lsampl_t data[2];
     comedi_insn insn;
     insn.subdev =3D 2; // PWM subdevice
     insn.insn =3D INSN_CONFIG;
     insn.chanspec =3D channel; // 0 or 1
     insn.n =3D 2;
     insn.data =3D data;
     data[0] =3D INSN_CONFIG_GET_PWM_STATUS;
     ret =3D 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=20
stops most of the above instructions from working.  The problem is that=20
the driver is sending wrong command code to read the PWM status=20
register.  In the driver code at=20
<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/dr=
ivers/comedi/drivers/adv_pci1760.c?h=3Dv6.1>=20
the PCI1760_CMD_GET_STATUS macro should be defined as 0x07, not 0x03.=20
I'll send a patch to the Linux kernel mailing lists to get it fixed, but=20
it will be some time before it makes its way into the stable kernel=20
versions.

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

--=20
You received this message because you are subscribed to the Google Groups "=
Comedi: Linux Control and Measurement Device Interface" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to [email protected].
To view this discussion on the web visit https://groups.google.com/d/msgid/=
comedi_list/8c7a9db6-c092-d0c2-5633-49b340a7c265%40mev.co.uk.