diff --git a/Firmware/CMakeLists.txt b/Firmware/CMakeLists.txt index 88e3281..30e266c 100644 --- a/Firmware/CMakeLists.txt +++ b/Firmware/CMakeLists.txt @@ -58,6 +58,7 @@ target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_adc hardware_dma + hardware_pwm ) pico_add_extra_outputs(${PROJECT_NAME}) diff --git a/Firmware/src/main.cpp b/Firmware/src/main.cpp index b2c2ad1..3615ba2 100644 --- a/Firmware/src/main.cpp +++ b/Firmware/src/main.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include // Create device name array. const uint16_t who_am_i = 123; @@ -26,6 +28,9 @@ const uint32_t AI0_PIN = 26; const uint32_t AI1_PIN = 27; const uint32_t AI2_PIN = 28; const uint32_t AI_MASK = 0x7; +const uint32_t PWM_PIN = 0; +const uint32_t PWM_SLICE = pwm_gpio_to_slice_num(PWM_PIN); +const uint32_t PWM_CHANNEL = pwm_gpio_to_channel(PWM_PIN); // Harp App state. bool events_active = false; @@ -51,22 +56,35 @@ const int32_t adc_period_us = 4000; const int32_t adc_callback_delay_us = 80000; int adc_sample_channel; int adc_ctrl_channel; +static queue_t adc_queue; + +// Define queue item contents +#pragma pack(push, 1) +struct adc_queue_item_t +{ + uint64_t timestamp; + uint16_t analog_data[3]; +}; +#pragma pack(pop) +adc_queue_item_t adc_queue_current; // Harp App Register Setup. -const size_t reg_count = 8; +const size_t reg_count = 10; // Define register contents. #pragma pack(push, 1) struct app_regs_t { - volatile uint8_t di_state; - volatile uint8_t do_set; - volatile uint8_t do_clear; - volatile uint8_t do_toggle; - volatile uint8_t do_state; - volatile uint32_t start_pulse_train[4]; - volatile uint8_t stop_pulse_train; - volatile uint16_t analog_data[3]; + volatile uint8_t di_state; // 32 + volatile uint8_t do_set; // 33 + volatile uint8_t do_clear; // 34 + volatile uint8_t do_toggle; // 35 + volatile uint8_t do_state; // 36 + volatile uint32_t start_pulse_train[4]; // 37 + volatile uint8_t stop_pulse_train; //38 + volatile uint16_t analog_data[3]; // 39 + volatile uint32_t pwm_config[2]; // 40 [0]=frequency in Hz, [1]=duty cycle (0-100) + volatile uint8_t pwm_stop; // 41 } app_regs; #pragma pack(pop) @@ -80,7 +98,9 @@ RegSpecs app_reg_specs[reg_count] {(uint8_t*)&app_regs.do_state, sizeof(app_regs.do_state), U8}, {(uint8_t*)&app_regs.start_pulse_train, sizeof(app_regs.start_pulse_train), U32}, {(uint8_t*)&app_regs.stop_pulse_train, sizeof(app_regs.stop_pulse_train), U8}, - {(uint8_t*)&app_regs.analog_data, sizeof(app_regs.analog_data), U16} + {(uint8_t*)&app_regs.analog_data, sizeof(app_regs.analog_data), U16}, + {(uint8_t*)&app_regs.pwm_config, sizeof(app_regs.pwm_config), U32}, + {(uint8_t*)&app_regs.pwm_stop, sizeof(app_regs.pwm_stop), U8} }; void gpio_callback(uint gpio, uint32_t events) @@ -203,14 +223,50 @@ bool adc_callback(repeating_timer_t *rt) rt->delay_us = -adc_period_us; // Mask the values to 12 bits (0xFFF) to ensure only valid ADC bits are used - app_regs.analog_data[0] = adc_vals[0] & 0xFFF; - app_regs.analog_data[1] = adc_vals[1] & 0xFFF; - app_regs.analog_data[2] = adc_vals[2] & 0xFFF; - - HarpCore::send_harp_reply(EVENT, APP_REG_START_ADDRESS + 7); + adc_queue_item_t item; + item.timestamp = HarpCore::harp_time_us_64(); + item.analog_data[0] = adc_vals[0] & 0xFFF; + item.analog_data[1] = adc_vals[1] & 0xFFF; + item.analog_data[2] = adc_vals[2] & 0xFFF; + queue_add_blocking(&adc_queue, &item); return true; } +void write_pwm_config(msg_t &msg) +{ + HarpCore::copy_msg_payload_to_register(msg); + + uint32_t frequency = app_regs.pwm_config[0]; + uint32_t duty_percent = app_regs.pwm_config[1]; + + if (duty_percent > 100) duty_percent = 100; + + // Assume 125MHz for the 2040 + float clock_div = 125.0f; + uint32_t wrap = 1000000 / frequency; // At 1MHz, this gives us cycles per PWM period + uint32_t level = (wrap * duty_percent) / 100; + + pwm_config config = pwm_get_default_config(); + pwm_config_set_clkdiv(&config, clock_div); + pwm_config_set_wrap(&config, wrap - 1); // Wrap is 0-based + + pwm_init(PWM_SLICE, &config, true); + pwm_set_chan_level(PWM_SLICE, PWM_CHANNEL, level); + + HarpCore::send_harp_reply(WRITE, msg.header.address); +} + +void write_pwm_stop(msg_t &msg) +{ + HarpCore::copy_msg_payload_to_register(msg); + + pwm_set_enabled(PWM_SLICE, false); + gpio_put(PWM_PIN, false); + + HarpCore::send_harp_reply(WRITE, msg.header.address); +} + + // Define register read-and-write handler functions. RegFnPair reg_handler_fns[reg_count] { @@ -221,7 +277,9 @@ RegFnPair reg_handler_fns[reg_count] {&HarpCore::read_reg_generic, &write_do_state}, {&HarpCore::read_reg_generic, &write_start_pulse_train}, {&HarpCore::read_reg_generic, &write_stop_pulse_train}, - {&HarpCore::read_reg_generic, &HarpCore::write_to_read_only_reg_error} + {&HarpCore::read_reg_generic, &HarpCore::write_to_read_only_reg_error}, + {&HarpCore::read_reg_generic, &write_pwm_config}, + {&HarpCore::read_reg_generic, &write_pwm_stop} }; void app_reset() @@ -239,6 +297,13 @@ void app_reset() app_regs.analog_data[0] = 0; app_regs.analog_data[1] = 0; app_regs.analog_data[2] = 0; + app_regs.pwm_config[0] = 1000; + app_regs.pwm_config[1] = 50; + app_regs.pwm_stop = 0; + + pwm_set_enabled(PWM_SLICE, false); + gpio_put(PWM_PIN, false); + } void configure_gpio(void) @@ -248,6 +313,8 @@ void configure_gpio(void) gpio_set_dir_in_masked(DI_MASK); gpio_clr_mask(DO_MASK); + gpio_set_function(PWM_PIN, GPIO_FUNC_PWM); + gpio_set_irq_callback(gpio_callback); gpio_set_irq_enabled(2, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true); gpio_set_irq_enabled(3, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true); @@ -324,6 +391,10 @@ void configure_adc(void) 1, // Number of word transfers. false // Don't Start immediately. ); + + // Configure queue for storing sample data and avoid concurrency in + // outbound message buffers, i.e. avoid sending reply in timer callback. + queue_init(&adc_queue, sizeof(adc_queue_item_t), 2); } void enable_adc_events() @@ -375,12 +446,23 @@ void update_app_state() } else if (events_active && !HarpCore::events_enabled()) { + // disable PWM + pwm_set_enabled(PWM_SLICE, false); + gpio_put(PWM_PIN, false); // disable events enable_gpio(false); disable_adc_events(); cancel_pulse_timers(); events_active = false; } + + if (events_active && queue_try_remove(&adc_queue, &adc_queue_current)) + { + app_regs.analog_data[0] = adc_queue_current.analog_data[0]; + app_regs.analog_data[1] = adc_queue_current.analog_data[1]; + app_regs.analog_data[2] = adc_queue_current.analog_data[2]; + HarpCore::send_harp_reply(EVENT, APP_REG_START_ADDRESS + 7, adc_queue_current.timestamp); + } } // Create Harp App. @@ -408,3 +490,4 @@ int main() app.run(); } } + diff --git a/Interface/Harp.Hobgoblin/AsyncDevice.Generated.cs b/Interface/Harp.Hobgoblin/AsyncDevice.Generated.cs index dc0da0a..7cd95ae 100644 --- a/Interface/Harp.Hobgoblin/AsyncDevice.Generated.cs +++ b/Interface/Harp.Hobgoblin/AsyncDevice.Generated.cs @@ -387,5 +387,97 @@ public async Task> ReadTimestampedAnalogDataAsync var reply = await CommandAsync(HarpCommand.ReadUInt16(AnalogData.Address), cancellationToken); return AnalogData.GetTimestampedPayload(reply); } + + /// + /// Asynchronously reads the contents of the StartPwm register. + /// + /// + /// A which can be used to cancel the operation. + /// + /// + /// A task that represents the asynchronous read operation. The + /// property contains the register payload. + /// + public async Task ReadStartPwmAsync(CancellationToken cancellationToken = default) + { + var reply = await CommandAsync(HarpCommand.ReadUInt32(StartPwm.Address), cancellationToken); + return StartPwm.GetPayload(reply); + } + + /// + /// Asynchronously reads the timestamped contents of the StartPwm register. + /// + /// + /// A which can be used to cancel the operation. + /// + /// + /// A task that represents the asynchronous read operation. The + /// property contains the timestamped register payload. + /// + public async Task> ReadTimestampedStartPwmAsync(CancellationToken cancellationToken = default) + { + var reply = await CommandAsync(HarpCommand.ReadUInt32(StartPwm.Address), cancellationToken); + return StartPwm.GetTimestampedPayload(reply); + } + + /// + /// Asynchronously writes a value to the StartPwm register. + /// + /// The value to be stored in the register. + /// + /// A which can be used to cancel the operation. + /// + /// The task object representing the asynchronous write operation. + public async Task WriteStartPwmAsync(StartPwmPayload value, CancellationToken cancellationToken = default) + { + var request = StartPwm.FromPayload(MessageType.Write, value); + await CommandAsync(request, cancellationToken); + } + + /// + /// Asynchronously reads the contents of the StopPwm register. + /// + /// + /// A which can be used to cancel the operation. + /// + /// + /// A task that represents the asynchronous read operation. The + /// property contains the register payload. + /// + public async Task ReadStopPwmAsync(CancellationToken cancellationToken = default) + { + var reply = await CommandAsync(HarpCommand.ReadByte(StopPwm.Address), cancellationToken); + return StopPwm.GetPayload(reply); + } + + /// + /// Asynchronously reads the timestamped contents of the StopPwm register. + /// + /// + /// A which can be used to cancel the operation. + /// + /// + /// A task that represents the asynchronous read operation. The + /// property contains the timestamped register payload. + /// + public async Task> ReadTimestampedStopPwmAsync(CancellationToken cancellationToken = default) + { + var reply = await CommandAsync(HarpCommand.ReadByte(StopPwm.Address), cancellationToken); + return StopPwm.GetTimestampedPayload(reply); + } + + /// + /// Asynchronously writes a value to the StopPwm register. + /// + /// The value to be stored in the register. + /// + /// A which can be used to cancel the operation. + /// + /// The task object representing the asynchronous write operation. + public async Task WriteStopPwmAsync(byte value, CancellationToken cancellationToken = default) + { + var request = StopPwm.FromPayload(MessageType.Write, value); + await CommandAsync(request, cancellationToken); + } } } diff --git a/Interface/Harp.Hobgoblin/Device.Generated.cs b/Interface/Harp.Hobgoblin/Device.Generated.cs index 5ee0944..63bdd3f 100644 --- a/Interface/Harp.Hobgoblin/Device.Generated.cs +++ b/Interface/Harp.Hobgoblin/Device.Generated.cs @@ -44,7 +44,9 @@ public Device() : base(WhoAmI) { } { 36, typeof(DigitalOutputState) }, { 37, typeof(StartPulseTrain) }, { 38, typeof(StopPulseTrain) }, - { 39, typeof(AnalogData) } + { 39, typeof(AnalogData) }, + { 40, typeof(StartPwm) }, + { 41, typeof(StopPwm) } }; /// @@ -266,6 +268,8 @@ public IObservable> Process(IObservable /// /// + /// + /// [XmlInclude(typeof(DigitalInputState))] [XmlInclude(typeof(DigitalOutputSet))] [XmlInclude(typeof(DigitalOutputClear))] @@ -274,6 +278,8 @@ public IObservable> Process(IObservable /// /// + /// + /// [XmlInclude(typeof(DigitalInputState))] [XmlInclude(typeof(DigitalOutputSet))] [XmlInclude(typeof(DigitalOutputClear))] @@ -311,6 +319,8 @@ string INamedElement.Name [XmlInclude(typeof(StartPulseTrain))] [XmlInclude(typeof(StopPulseTrain))] [XmlInclude(typeof(AnalogData))] + [XmlInclude(typeof(StartPwm))] + [XmlInclude(typeof(StopPwm))] [XmlInclude(typeof(TimestampedDigitalInputState))] [XmlInclude(typeof(TimestampedDigitalOutputSet))] [XmlInclude(typeof(TimestampedDigitalOutputClear))] @@ -319,6 +329,8 @@ string INamedElement.Name [XmlInclude(typeof(TimestampedStartPulseTrain))] [XmlInclude(typeof(TimestampedStopPulseTrain))] [XmlInclude(typeof(TimestampedAnalogData))] + [XmlInclude(typeof(TimestampedStartPwm))] + [XmlInclude(typeof(TimestampedStopPwm))] [Description("Filters and selects specific messages reported by the Hobgoblin device.")] public partial class Parse : ParseBuilder, INamedElement { @@ -345,6 +357,8 @@ public Parse() /// /// /// + /// + /// [XmlInclude(typeof(DigitalInputState))] [XmlInclude(typeof(DigitalOutputSet))] [XmlInclude(typeof(DigitalOutputClear))] @@ -353,6 +367,8 @@ public Parse() [XmlInclude(typeof(StartPulseTrain))] [XmlInclude(typeof(StopPulseTrain))] [XmlInclude(typeof(AnalogData))] + [XmlInclude(typeof(StartPwm))] + [XmlInclude(typeof(StopPwm))] [Description("Formats a sequence of values as specific Hobgoblin register messages.")] public partial class Format : FormatBuilder, INamedElement { @@ -1183,6 +1199,216 @@ public static Timestamped GetPayload(HarpMessage message) } } + /// + /// Represents a register that starts the PWM feature on GPIO0. + /// + [Description("Starts the PWM feature on GPIO0.")] + public partial class StartPwm + { + /// + /// Represents the address of the register. This field is constant. + /// + public const int Address = 40; + + /// + /// Represents the payload type of the register. This field is constant. + /// + public const PayloadType RegisterType = PayloadType.U32; + + /// + /// Represents the length of the register. This field is constant. + /// + public const int RegisterLength = 2; + + static StartPwmPayload ParsePayload(uint[] payload) + { + StartPwmPayload result; + result.Frequency = payload[0]; + result.DutyCycle = payload[1]; + return result; + } + + static uint[] FormatPayload(StartPwmPayload value) + { + uint[] result; + result = new uint[2]; + result[0] = value.Frequency; + result[1] = value.DutyCycle; + return result; + } + + /// + /// Returns the payload data for register messages. + /// + /// A object representing the register message. + /// A value representing the message payload. + public static StartPwmPayload GetPayload(HarpMessage message) + { + return ParsePayload(message.GetPayloadArray()); + } + + /// + /// Returns the timestamped payload data for register messages. + /// + /// A object representing the register message. + /// A value representing the timestamped message payload. + public static Timestamped GetTimestampedPayload(HarpMessage message) + { + var payload = message.GetTimestampedPayloadArray(); + return Timestamped.Create(ParsePayload(payload.Value), payload.Seconds); + } + + /// + /// Returns a Harp message for the register. + /// + /// The type of the Harp message. + /// The value to be stored in the message payload. + /// + /// A object for the register + /// with the specified message type and payload. + /// + public static HarpMessage FromPayload(MessageType messageType, StartPwmPayload value) + { + return HarpMessage.FromUInt32(Address, messageType, FormatPayload(value)); + } + + /// + /// Returns a timestamped Harp message for the + /// register. + /// + /// The timestamp of the message payload, in seconds. + /// The type of the Harp message. + /// The value to be stored in the message payload. + /// + /// A object for the register + /// with the specified message type, timestamp, and payload. + /// + public static HarpMessage FromPayload(double timestamp, MessageType messageType, StartPwmPayload value) + { + return HarpMessage.FromUInt32(Address, timestamp, messageType, FormatPayload(value)); + } + } + + /// + /// Provides methods for manipulating timestamped messages from the + /// StartPwm register. + /// + /// + [Description("Filters and selects timestamped messages from the StartPwm register.")] + public partial class TimestampedStartPwm + { + /// + /// Represents the address of the register. This field is constant. + /// + public const int Address = StartPwm.Address; + + /// + /// Returns timestamped payload data for register messages. + /// + /// A object representing the register message. + /// A value representing the timestamped message payload. + public static Timestamped GetPayload(HarpMessage message) + { + return StartPwm.GetTimestampedPayload(message); + } + } + + /// + /// Represents a register that writing any value will stop the PWM generation on GPIO0. + /// + [Description("Writing any value will stop the PWM generation on GPIO0.")] + public partial class StopPwm + { + /// + /// Represents the address of the register. This field is constant. + /// + public const int Address = 41; + + /// + /// Represents the payload type of the register. This field is constant. + /// + public const PayloadType RegisterType = PayloadType.U8; + + /// + /// Represents the length of the register. This field is constant. + /// + public const int RegisterLength = 1; + + /// + /// Returns the payload data for register messages. + /// + /// A object representing the register message. + /// A value representing the message payload. + public static byte GetPayload(HarpMessage message) + { + return message.GetPayloadByte(); + } + + /// + /// Returns the timestamped payload data for register messages. + /// + /// A object representing the register message. + /// A value representing the timestamped message payload. + public static Timestamped GetTimestampedPayload(HarpMessage message) + { + return message.GetTimestampedPayloadByte(); + } + + /// + /// Returns a Harp message for the register. + /// + /// The type of the Harp message. + /// The value to be stored in the message payload. + /// + /// A object for the register + /// with the specified message type and payload. + /// + public static HarpMessage FromPayload(MessageType messageType, byte value) + { + return HarpMessage.FromByte(Address, messageType, value); + } + + /// + /// Returns a timestamped Harp message for the + /// register. + /// + /// The timestamp of the message payload, in seconds. + /// The type of the Harp message. + /// The value to be stored in the message payload. + /// + /// A object for the register + /// with the specified message type, timestamp, and payload. + /// + public static HarpMessage FromPayload(double timestamp, MessageType messageType, byte value) + { + return HarpMessage.FromByte(Address, timestamp, messageType, value); + } + } + + /// + /// Provides methods for manipulating timestamped messages from the + /// StopPwm register. + /// + /// + [Description("Filters and selects timestamped messages from the StopPwm register.")] + public partial class TimestampedStopPwm + { + /// + /// Represents the address of the register. This field is constant. + /// + public const int Address = StopPwm.Address; + + /// + /// Returns timestamped payload data for register messages. + /// + /// A object representing the register message. + /// A value representing the timestamped message payload. + public static Timestamped GetPayload(HarpMessage message) + { + return StopPwm.GetTimestampedPayload(message); + } + } + /// /// Represents an operator which creates standard message payloads for the /// Hobgoblin device. @@ -1195,6 +1421,8 @@ public static Timestamped GetPayload(HarpMessage message) /// /// /// + /// + /// [XmlInclude(typeof(CreateDigitalInputStatePayload))] [XmlInclude(typeof(CreateDigitalOutputSetPayload))] [XmlInclude(typeof(CreateDigitalOutputClearPayload))] @@ -1203,6 +1431,8 @@ public static Timestamped GetPayload(HarpMessage message) [XmlInclude(typeof(CreateStartPulseTrainPayload))] [XmlInclude(typeof(CreateStopPulseTrainPayload))] [XmlInclude(typeof(CreateAnalogDataPayload))] + [XmlInclude(typeof(CreateStartPwmPayload))] + [XmlInclude(typeof(CreateStopPwmPayload))] [XmlInclude(typeof(CreateTimestampedDigitalInputStatePayload))] [XmlInclude(typeof(CreateTimestampedDigitalOutputSetPayload))] [XmlInclude(typeof(CreateTimestampedDigitalOutputClearPayload))] @@ -1211,6 +1441,8 @@ public static Timestamped GetPayload(HarpMessage message) [XmlInclude(typeof(CreateTimestampedStartPulseTrainPayload))] [XmlInclude(typeof(CreateTimestampedStopPulseTrainPayload))] [XmlInclude(typeof(CreateTimestampedAnalogDataPayload))] + [XmlInclude(typeof(CreateTimestampedStartPwmPayload))] + [XmlInclude(typeof(CreateTimestampedStopPwmPayload))] [Description("Creates standard message payloads for the Hobgoblin device.")] public partial class CreateMessage : CreateMessageBuilder, INamedElement { @@ -1696,6 +1928,123 @@ public HarpMessage GetMessage(double timestamp, MessageType messageType) } } + /// + /// Represents an operator that creates a message payload + /// that starts the PWM feature on GPIO0. + /// + [DisplayName("StartPwmPayload")] + [Description("Creates a message payload that starts the PWM feature on GPIO0.")] + public partial class CreateStartPwmPayload + { + /// + /// Gets or sets a value that specifies the frequency in Hz of the PWM signal. + /// + [Description("Specifies the frequency in Hz of the PWM signal.")] + public uint Frequency { get; set; } = 10000; + + /// + /// Gets or sets a value that specifies the duty cycle of the PWM signal as a percentage (0-100). + /// + [Description("Specifies the duty cycle of the PWM signal as a percentage (0-100).")] + public uint DutyCycle { get; set; } = 50; + + /// + /// Creates a message payload for the StartPwm register. + /// + /// The created message payload value. + public StartPwmPayload GetPayload() + { + StartPwmPayload value; + value.Frequency = Frequency; + value.DutyCycle = DutyCycle; + return value; + } + + /// + /// Creates a message that starts the PWM feature on GPIO0. + /// + /// Specifies the type of the created message. + /// A new message for the StartPwm register. + public HarpMessage GetMessage(MessageType messageType) + { + return Harp.Hobgoblin.StartPwm.FromPayload(messageType, GetPayload()); + } + } + + /// + /// Represents an operator that creates a timestamped message payload + /// that starts the PWM feature on GPIO0. + /// + [DisplayName("TimestampedStartPwmPayload")] + [Description("Creates a timestamped message payload that starts the PWM feature on GPIO0.")] + public partial class CreateTimestampedStartPwmPayload : CreateStartPwmPayload + { + /// + /// Creates a timestamped message that starts the PWM feature on GPIO0. + /// + /// The timestamp of the message payload, in seconds. + /// Specifies the type of the created message. + /// A new timestamped message for the StartPwm register. + public HarpMessage GetMessage(double timestamp, MessageType messageType) + { + return Harp.Hobgoblin.StartPwm.FromPayload(timestamp, messageType, GetPayload()); + } + } + + /// + /// Represents an operator that creates a message payload + /// that writing any value will stop the PWM generation on GPIO0. + /// + [DisplayName("StopPwmPayload")] + [Description("Creates a message payload that writing any value will stop the PWM generation on GPIO0.")] + public partial class CreateStopPwmPayload + { + /// + /// Gets or sets the value that writing any value will stop the PWM generation on GPIO0. + /// + [Description("The value that writing any value will stop the PWM generation on GPIO0.")] + public byte StopPwm { get; set; } + + /// + /// Creates a message payload for the StopPwm register. + /// + /// The created message payload value. + public byte GetPayload() + { + return StopPwm; + } + + /// + /// Creates a message that writing any value will stop the PWM generation on GPIO0. + /// + /// Specifies the type of the created message. + /// A new message for the StopPwm register. + public HarpMessage GetMessage(MessageType messageType) + { + return Harp.Hobgoblin.StopPwm.FromPayload(messageType, GetPayload()); + } + } + + /// + /// Represents an operator that creates a timestamped message payload + /// that writing any value will stop the PWM generation on GPIO0. + /// + [DisplayName("TimestampedStopPwmPayload")] + [Description("Creates a timestamped message payload that writing any value will stop the PWM generation on GPIO0.")] + public partial class CreateTimestampedStopPwmPayload : CreateStopPwmPayload + { + /// + /// Creates a timestamped message that writing any value will stop the PWM generation on GPIO0. + /// + /// The timestamp of the message payload, in seconds. + /// Specifies the type of the created message. + /// A new timestamped message for the StopPwm register. + public HarpMessage GetMessage(double timestamp, MessageType messageType) + { + return Harp.Hobgoblin.StopPwm.FromPayload(timestamp, messageType, GetPayload()); + } + } + /// /// Represents the payload of the StartPulseTrain register. /// @@ -1813,6 +2162,51 @@ public override string ToString() } } + /// + /// Represents the payload of the StartPwm register. + /// + public struct StartPwmPayload + { + /// + /// Initializes a new instance of the structure. + /// + /// Specifies the frequency in Hz of the PWM signal. + /// Specifies the duty cycle of the PWM signal as a percentage (0-100). + public StartPwmPayload( + uint frequency, + uint dutyCycle) + { + Frequency = frequency; + DutyCycle = dutyCycle; + } + + /// + /// Specifies the frequency in Hz of the PWM signal. + /// + public uint Frequency; + + /// + /// Specifies the duty cycle of the PWM signal as a percentage (0-100). + /// + public uint DutyCycle; + + /// + /// Returns a that represents the payload of + /// the StartPwm register. + /// + /// + /// A that represents the payload of the + /// StartPwm register. + /// + public override string ToString() + { + return "StartPwmPayload { " + + "Frequency = " + Frequency + ", " + + "DutyCycle = " + DutyCycle + " " + + "}"; + } + } + /// /// Specifies the state of port digital input lines. /// diff --git a/Interface/Harp.Hobgoblin/Harp.Hobgoblin.csproj b/Interface/Harp.Hobgoblin/Harp.Hobgoblin.csproj index 079d0ea..4235636 100644 --- a/Interface/Harp.Hobgoblin/Harp.Hobgoblin.csproj +++ b/Interface/Harp.Hobgoblin/Harp.Hobgoblin.csproj @@ -16,7 +16,7 @@ README.md ..\bin\$(Configuration) net462;netstandard2.0 - 0.1.0 + 0.1.1 9.0 diff --git a/device.yml b/device.yml index 77c47b3..0426e5a 100644 --- a/device.yml +++ b/device.yml @@ -77,6 +77,26 @@ registers: AnalogInput2: offset: 2 description: The analog value sampled from ADC channel 2. + StartPwm: + address: 40 + type: U32 + length: 2 + access: Write + description: Starts the PWM feature on GPIO0. + payloadSpec: + Frequency: + offset: 0 + defaultValue: 10000 + description: Specifies the frequency in Hz of the PWM signal. + DutyCycle: + offset: 1 + defaultValue: 50 + description: Specifies the duty cycle of the PWM signal as a percentage (0-100). + StopPwm: + address: 41 + type: U8 + access: Write + description: Writing any value will stop the PWM generation on GPIO0. bitMasks: DigitalInputs: description: Specifies the state of port digital input lines.