rt_drv_pwm.c 10.8 KB
Newer Older
1
/*
2
 * Copyright (c) 2006-2022, RT-Thread Development Team
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
5 6 7 8
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-05-07     aozima       the first version
9
 * 2022-05-14     Stanley Lwin add pwm function
10
 * 2022-07-25     liYony       fix complementary outputs and add usage information in finsh
11
 * 2022-08-31     liYony       Add complementary output section to framework for management
12 13
 */

mysterywolf's avatar
mysterywolf 已提交
14
#include <rtdevice.h>
15 16 17 18 19

static rt_err_t _pwm_control(rt_device_t dev, int cmd, void *args)
{
    rt_err_t result = RT_EOK;
    struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
20
    struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)args;
21

22
    switch (cmd)
23
    {
24 25 26 27 28 29 30 31 32 33
        case PWMN_CMD_ENABLE:
            configuration->complementary = RT_TRUE;
            break;
        case PWMN_CMD_DISABLE:
            configuration->complementary = RT_FALSE;
            break;
        default:
            if(pwm->ops->control)
                result = pwm->ops->control(pwm, cmd, args);
            break;
34
    }
35

36
    return result;
37 38 39 40 41 42 43 44 45 46 47 48 49
}


/*
pos: channel
void *buffer: rt_uint32_t pulse[size]
size : number of pulse, only set to sizeof(rt_uint32_t).
*/
static rt_size_t _pwm_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    rt_err_t result = RT_EOK;
    struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
    rt_uint32_t *pulse = (rt_uint32_t *)buffer;
50 51
    struct rt_pwm_configuration configuration = {0};

52
    configuration.channel = (pos > 0) ? (pos) : (-pos);
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

    if (pwm->ops->control)
    {
        result = pwm->ops->control(pwm, PWM_CMD_GET,  &configuration);
        if (result != RT_EOK)
        {
            return 0;
        }

        *pulse = configuration.pulse;
    }

    return size;
}

/*
pos: channel
void *buffer: rt_uint32_t pulse[size]
size : number of pulse, only set to sizeof(rt_uint32_t).
*/
static rt_size_t _pwm_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    rt_err_t result = RT_EOK;
    struct rt_device_pwm *pwm = (struct rt_device_pwm *)dev;
    rt_uint32_t *pulse = (rt_uint32_t *)buffer;
78
    struct rt_pwm_configuration configuration = {0};
79

80
    configuration.channel = (pos > 0) ? (pos) : (-pos);
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101

    if (pwm->ops->control)
    {
        result = pwm->ops->control(pwm, PWM_CMD_GET, &configuration);
        if (result != RT_EOK)
        {
            return 0;
        }

        configuration.pulse = *pulse;

        result = pwm->ops->control(pwm, PWM_CMD_SET, &configuration);
        if (result != RT_EOK)
        {
            return 0;
        }
    }

    return size;
}

102 103 104 105 106 107 108 109 110 111 112 113
#ifdef RT_USING_DEVICE_OPS
static const struct rt_device_ops pwm_device_ops =
{
    RT_NULL,
    RT_NULL,
    RT_NULL,
    _pwm_read,
    _pwm_write,
    _pwm_control
};
#endif /* RT_USING_DEVICE_OPS */

114 115 116 117
rt_err_t rt_device_pwm_register(struct rt_device_pwm *device, const char *name, const struct rt_pwm_ops *ops, const void *user_data)
{
    rt_err_t result = RT_EOK;

118
    rt_memset(device, 0, sizeof(struct rt_device_pwm));
119

120 121 122 123 124 125 126 127 128 129
#ifdef RT_USING_DEVICE_OPS
    device->parent.ops = &pwm_device_ops;
#else
    device->parent.init = RT_NULL;
    device->parent.open = RT_NULL;
    device->parent.close = RT_NULL;
    device->parent.read  = _pwm_read;
    device->parent.write = _pwm_write;
    device->parent.control = _pwm_control;
#endif /* RT_USING_DEVICE_OPS */
130

131
    device->parent.type         = RT_Device_Class_PWM;
132 133 134 135 136 137 138 139
    device->ops                 = ops;
    device->parent.user_data    = (void *)user_data;

    result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);

    return result;
}

140
rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel)
141 142 143 144 145 146 147 148 149
{
    rt_err_t result = RT_EOK;
    struct rt_pwm_configuration configuration = {0};

    if (!device)
    {
        return -RT_EIO;
    }

150 151 152 153 154 155 156 157 158 159 160 161 162 163
    /* Make it is positive num forever */
    configuration.channel = (channel > 0) ? (channel) : (-channel);

    /* If channel is a positive number (0 ~ n), it means using normal output pin.
     * If channel is a negative number (0 ~ -n), it means using complementary output pin. */
    if(channel > 0)
    {
        result = rt_device_control(&device->parent, PWMN_CMD_DISABLE, &configuration);
    }
    else
    {
        result = rt_device_control(&device->parent, PWMN_CMD_ENABLE, &configuration);
    }

164 165 166 167 168
    result = rt_device_control(&device->parent, PWM_CMD_ENABLE, &configuration);

    return result;
}

169
rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel)
170 171
{
    rt_err_t result = RT_EOK;
172 173 174 175 176 177 178
    struct rt_pwm_configuration configuration = {0};

    if (!device)
    {
        return -RT_EIO;
    }

179 180 181 182 183 184 185 186 187 188 189 190 191 192
    /* Make it is positive num forever */
    configuration.channel = (channel > 0) ? (channel) : (-channel);

    /* If channel is a positive number (0 ~ n), it means using normal output pin.
     * If channel is a negative number (0 ~ -n), it means using complementary output pin. */
    if(channel > 0)
    {
        result = rt_device_control(&device->parent, PWMN_CMD_DISABLE, &configuration);
    }
    else
    {
        result = rt_device_control(&device->parent, PWMN_CMD_ENABLE, &configuration);
    }

193
    result = rt_device_control(&device->parent, PWM_CMD_DISABLE, &configuration);
194

195
    return result;
196 197
}

198
rt_err_t rt_pwm_set(struct rt_device_pwm *device, int channel, rt_uint32_t period, rt_uint32_t pulse)
199 200
{
    rt_err_t result = RT_EOK;
201 202 203 204 205 206 207
    struct rt_pwm_configuration configuration = {0};

    if (!device)
    {
        return -RT_EIO;
    }

208
    configuration.channel = (channel > 0) ? (channel) : (-channel);
209 210
    configuration.period = period;
    configuration.pulse = pulse;
211
    result = rt_device_control(&device->parent, PWM_CMD_SET, &configuration);
212 213 214 215

    return result;
}

216 217 218 219 220 221 222 223 224 225
rt_err_t rt_pwm_set_period(struct rt_device_pwm *device, int channel, rt_uint32_t period)
{
    rt_err_t result = RT_EOK;
    struct rt_pwm_configuration configuration = {0};

    if (!device)
    {
        return -RT_EIO;
    }

226
    configuration.channel = (channel > 0) ? (channel) : (-channel);
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
    configuration.period = period;
    result = rt_device_control(&device->parent, PWM_CMD_SET_PERIOD, &configuration);

    return result;
}

rt_err_t rt_pwm_set_pulse(struct rt_device_pwm *device, int channel, rt_uint32_t pulse)
{
    rt_err_t result = RT_EOK;
    struct rt_pwm_configuration configuration = {0};

    if (!device)
    {
        return -RT_EIO;
    }

243
    configuration.channel = (channel > 0) ? (channel) : (-channel);
244 245 246 247 248 249
    configuration.pulse = pulse;
    result = rt_device_control(&device->parent, PWM_CMD_SET_PULSE, &configuration);

    return result;
}

250 251 252 253 254 255 256 257 258 259 260 261 262 263
rt_err_t rt_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *cfg)
{
    rt_err_t result = RT_EOK;

    if (!device)
    {
        return -RT_EIO;
    }

    result = rt_device_control(&device->parent, PWM_CMD_GET, cfg);

    return result;
}

264
#ifdef RT_USING_FINSH
mysterywolf's avatar
mysterywolf 已提交
265
#include <stdlib.h>
266
#include <string.h>
267 268
#include <finsh.h>

269
static int pwm(int argc, char **argv)
270
{
271 272 273
    rt_err_t result = -RT_ERROR;
    char *result_str;
    static struct rt_device_pwm *pwm_device = RT_NULL;
274 275
    struct rt_pwm_configuration cfg = {0};

276
    if(argc > 1)
277
    {
278 279 280 281 282 283 284 285 286 287
        if(!strcmp(argv[1], "probe"))
        {
            if(argc == 3)
            {
                pwm_device = (struct rt_device_pwm *)rt_device_find(argv[2]);
                result_str = (pwm_device == RT_NULL) ? "failure" : "success";
                rt_kprintf("probe %s %s\n", argv[2], result_str);
            }
            else
            {
288
                rt_kprintf("pwm probe <device name>                  - probe pwm by name\n");
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
            }
        }
        else
        {
            if(pwm_device == RT_NULL)
            {
                rt_kprintf("Please using 'pwm probe <device name>' first.\n");
                return -RT_ERROR;
            }
            if(!strcmp(argv[1], "enable"))
            {
                if(argc == 3)
                {
                    result = rt_pwm_enable(pwm_device, atoi(argv[2]));
                    result_str = (result == RT_EOK) ? "success" : "failure";
                    rt_kprintf("%s channel %d is enabled %s \n", pwm_device->parent.parent.name, atoi(argv[2]), result_str);
                }
                else
                {
308 309 310
                    rt_kprintf("pwm enable <channel>                     - enable pwm channel\n");
                    rt_kprintf("    e.g. MSH >pwm enable  1              - PWM_CH1  nomal\n");
                    rt_kprintf("    e.g. MSH >pwm enable -1              - PWM_CH1N complememtary\n");
311
                }
312
            }
313 314 315 316 317 318 319 320
            else if(!strcmp(argv[1], "disable"))
            {
                if(argc == 3)
                {
                    result = rt_pwm_disable(pwm_device, atoi(argv[2]));
                }
                else
                {
321
                    rt_kprintf("pwm disable <channel>                    - disable pwm channel\n");
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
                }
            }
            else if(!strcmp(argv[1], "get"))
            {
                cfg.channel = atoi(argv[2]);
                result = rt_pwm_get(pwm_device, &cfg);
                if(result == RT_EOK)
                {
                    rt_kprintf("Info of device [%s] channel [%d]:\n",pwm_device, atoi(argv[2]));
                    rt_kprintf("period      : %d\n", cfg.period);
                    rt_kprintf("pulse       : %d\n", cfg.pulse);
                    rt_kprintf("Duty cycle  : %d%%\n",(int)(((double)(cfg.pulse)/(cfg.period)) * 100));
                }
                else
                {
                    rt_kprintf("Get info of device: [%s] error.\n", pwm_device);
                }
            }
            else if (!strcmp(argv[1], "set"))
            {
                if(argc == 5)
                {
                    result = rt_pwm_set(pwm_device, atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
                    rt_kprintf("pwm info set on %s at channel %d\n",pwm_device,atoi(argv[2]));
                }
                else
                {
                    rt_kprintf("Set info of device: [%s] error\n", pwm_device);
                    rt_kprintf("Usage: pwm set <channel> <period> <pulse>\n");
                }
            }

            else
            {
356
                rt_kprintf("pwm get <channel>                        - get pwm channel info\n");
357 358
            }
        }
359 360 361
    }
    else
    {
362
        rt_kprintf("Usage: \n");
363 364 365 366 367
        rt_kprintf("pwm probe   <device name>                - probe pwm by name\n");
        rt_kprintf("pwm enable  <channel>                    - enable pwm channel\n");
        rt_kprintf("pwm disable <channel>                    - disable pwm channel\n");
        rt_kprintf("pwm get     <channel>                    - get pwm channel info\n");
        rt_kprintf("pwm set     <channel> <period> <pulse>   - set pwm channel info\n");
368 369

        result = - RT_ERROR;
370 371
    }

372
    return RT_EOK;
373
}
374
MSH_CMD_EXPORT(pwm, pwm [option]);
375

马志远 已提交
376
#endif /* RT_USING_FINSH */