В Linux с ШИМ (PWM) уже работали в публикации LED, ШИМ (PWM), КНОПКА. Управление PWM осуществлялось через виртуальную файловую систему sysfs. Далее, в публикации Работа с GPIO в Linux. Часть 7. Управление подсветкой (backlight) экрана используя ШИМ (PWM) использовали устройство в Linux pwm-backlight, которое создавало интерфейс для управления подсветкой по пути /sys/class/backlight . Теперь будем управлять PWM из .NET кода, язык программирования C#. Среда .NET работает с PWM посредством обертки над файловой системой sysfs, поэтому для продолжения чтения желательно ознакомится с материалом публикации LED, ШИМ (PWM), КНОПКА.
Оглавление
- Постановка задачи
- Подготовка устройства
- Подготовка среды запуска (ПК)
- Управление PWM в Linux из .NET кода
- Устройство класса PwmChannel
- Литература
Постановка задачи
Реализовать управление подсветкой экрана SPI LCD ILI9341 через ШИМ (PWM) из .NET кода на C#.
- Плата Banana Pi BPI-M64 установлена версия Armbian_21.02.1_Bananapim64_bionic_current_5.10.12_minimal.img.xz, основана на Ubuntu 18.04.5 LTS (Bionic Beaver), ядро Linux 5.10.12. uname: Linux bananapim64 5.10.12-sunxi64 #21.02.1 SMP Wed Feb 3 20:42:58 CET 2021 aarch64 aarch64 aarch64 GNU/Linux.
Подготовка устройства
Для управления PWM из .NET используется класс PwmChannel пространство имен System.Device.Pwm. Класс PwmChannel является оберткой над виртуальной файловой системой sysfs. Поэтому для использования PWM необходимо задействовать файл DTS sun50i-a64-r-pwm-pl10.dts. Но в публикации Работа с GPIO в Linux. Часть 7. Управление подсветкой (backlight) экрана используя ШИМ (PWM) мы включили DTS файл sun50i-a64-spi-ili9341-pwm-backlight.dts, который помимо дисплея включает устройство pwm-backlight. Если мы попытаемся управлять PWM из .NET кода, то получим исключение, что устройство занято. Поэтому для дисплея необходимо сменить файл DTS на sun50i-a64-spi-ili9341-led-always-on.dts из публикации Работа с GPIO в Linux на примере Banana Pi BPI-M64. Часть 4. Device Tree overlays. Подключение дисплея SPI LCD ILI9341 (Вариант 1. Схема подключения с постоянно включенной подсветкой).
Принципиальная схема подключения дисплея SPI LCD ILI9341 с PWM остается такая же, как и в публикации Работа с GPIO в Linux. Часть 7. Управление подсветкой (backlight) экрана используя ШИМ (PWM). Все что меняется это файл DTS для дисплея.
На плате Banana Pi BPI-M64 должна быть установлена платформа .NET Runtime 5.0 и отладчик vsdbg, как это сделать указано в публикации Удаленная отладка приложения на .NET 5.0 в Visual Studio Code для ARM на примере Banana Pi BPI-M64 и Cubietruck (Armbian, Linux). На этом подготовка устройства закончена.
Подготовка среды запуска (ПК)
Отладку будем запускать из среды Visual Studio Code на ПК под ОС Windows 7. Как установить и настроить среду в публикации Создание первого приложения на .NET 5.0 в Visual Studio Code для ARM.
Управление PWM в Linux из .NET кода
Создадим .NET 5.0 консольное приложение — dotnet-iot-pwm. Добавим Nuget-пакет System.Device.Gpio.
Разместим в Program.cs следующий программный код, который будет задавать коэффициент заполнения (duty cycle) от 0% до 100%:
static void Main(string[] args) { Console.WriteLine("Starting PWM Controller - Simple Demo"); const int chip= 0; // sysfs: /sys/class/pwm/pwmchip0 const int channel = 0; // sysfs: /sys/class/pwm/pwmchip0/pwm0 // const int frequency = 200; //Hz using (var _pwm = PwmChannel.Create(chip, channel, frequency,dutyCyclePercentage:0)) { _pwm.Start(); for (double fill = 0; fill <= 1;fill+=0.2) { Console.WriteLine("Duty cycle: {0, 0:n0}%", fill * 100); _pwm.DutyCycle = fill; Thread.Sleep(1700); } _pwm.Stop(); } Console.WriteLine("Closing the program"); }
Добавим пространство имен System.Device.Pwm. Для создания класса PwmChannel управления PWM используется метод:
var _pwm = PwmChannel.Create(chip, channel, frequency,dutyCyclePercentage:0)
В качестве параметров необходимо передать 4 аргумента: номер контроллера/чипа, номер канала, частота ШИМ, и коэффициент заполнения (значения от 0.0 до 1.0).
- Номер контроллера/чипа — 0 это в sysfs: /sys/class/pwm/pwmchip0 ;
- Номер канала — 0 это в sysfs: /sys/class/pwm/pwmchip0/pwm0 ;
- Частота — 200 Hz.
Далее, для включения PWM используется метод _pwm.Start(). В цикле от 0 до 1 с шагом 0.2, задаем коэффициент заполнения свойство _pwm.DutyCycle.
По итогу работы выполняем метод _pwm.Stop() для прекращения использования устройства PWM.
Демонстрация работы программного кода
Устройство класса PwmChannel
Когда вызывается метод PwmChannel.Create в зависимости от платформы Windows, BeagleBone или Unix создается соответствующий класс. В данном случае создается класс UnixPwmChannel из файла UnixPwmChannel.cs. В этом классе определяется доступ к sysfs и используются методы работы с PWM на уровне файловых потоков, это можно видеть на примере:
public UnixPwmChannel( int chip, int channel, int frequency = 400, double dutyCycle = 0.5) { _chip = chip; _channel = channel; _chipPath = $"/sys/class/pwm/pwmchip{_chip}"; _channelPath = $"{_chipPath}/{ChannelName}"; Validate(); Open(); // avoid opening the file for operations changing relatively frequently var dutyCycleFile = new FileStream($"{_channelPath}/duty_cycle", FileMode.Open, FileAccess.ReadWrite); _dutyCycleWriter = new StreamWriter(dutyCycleFile); _frequencyWriter = new StreamWriter(new FileStream($"{_channelPath}/period", FileMode.Open, FileAccess.ReadWrite)); int currentDutyCycleNs = GetCurrentDutyCycleNs(dutyCycleFile); SetFrequency(frequency, dutyCycle, currentDutyCycleNs); }
Переменные _chipPath и _channelPath, как раз и определяют путь к устройству в sysfs.
Приложение dotnet-iot-pwm на GitHub — .NET IoT Samples.