Skip navigation
1 2 3 Previous Next

Jan Cumps's Blog

99 posts

I'm trying out basic CAN communication on a Hercules microcontroller.

This first test is to test an example project.

Four CAN modules send an 8 char message out to themselves (so that we don't need external hardware).

 

What's tested here is how to set up CAN and how to use interrupt read-back.

 

 

 

The CAN example

 

This is the training code that comes with the HALCoGen configuration tool for Hercules.

It uses the controller's internal loop back mechanism to send messages to itself without going external.

This is an inherent part of the safety features of this controller: the ability to verify its own peripherals.

We use it here as part of a demo. In the Hercules safety library, this function is used to validate that the module works and fails safely.

 

 

I'm using a Hercules TMS570LC43 LaunchPad. The controller has 4 DAC modules. I enable all.

Then I configure a message sender (1) and receiver (2) for each of the 4 CANs. The message ID for sender and receiver have to be the same (I use 1), otherwise traffic is ignored by the receiver.

Interrupts are enabled on the receivers.

The image shows CAN #2. The setup is the same for all 4.

The high interrupts for the 4 CAN modules have to be enabled in the VIM table.

I'm showing CAN 1 here. It's interrupt 16.

the other ones are on position 35, 45 and 113.

 

The Code

 

We use a sender buffer for each of the 4 modules that contains dummy values (not really. It's Jack Kilby Day so I've adapted the content).

 

#define D_COUNT  8

uint8 tx_data1[D_COUNT] = {'J','a','c','k',' ', ' ',' ',' '};
uint8 tx_data2[D_COUNT] = {'K', 'i', 'l', 'b', 'y', ' ', ' ', ' '};
uint8 tx_data3[D_COUNT] = {'D', 'a', 'y', ' ', ' ', ' ', ' ', ' '};
uint8 tx_data4[D_COUNT] = {31,32,33,34,35,36,37,38};

 

The receive buffers are empty. At the end of the program they should get the same values as the send buffers.

 

uint8 rx_data1[D_COUNT] = {0};
uint8 rx_data2[D_COUNT] = {0};
uint8 rx_data3[D_COUNT] = {0};
uint8 rx_data4[D_COUNT] = {0};

 

At init time, we set the loop-back mode of the 4 CAN modules so that all traffic internally flows from the output to it's own input.

 

    /** - configuring CAN1 MB1,Msg ID-1 to transmit and CAN2 MB1 to receive */
    canInit();
    canEnableloopback(canREG1, Internal_Lbk);
    canEnableloopback(canREG2, Internal_Lbk);
    canEnableloopback(canREG3, Internal_Lbk);
    canEnableloopback(canREG4, Internal_Lbk);

 

The only thing the code will do is send the 4 messages. You will not find read functions here. That happens in the interrupt service handler.

 

    canTransmit(canREG1, canMESSAGE_BOX1, (const uint8 *) &tx_data1[0]);
    canTransmit(canREG2, canMESSAGE_BOX1, (const uint8 *) &tx_data2[0]);
    canTransmit(canREG3, canMESSAGE_BOX1, (const uint8 *) &tx_data3[0]);
    canTransmit(canREG4, canMESSAGE_BOX1, (const uint8 *) &tx_data4[0]);

 

The ISR receives the info and fills the receive buffers.

 

void canMessageNotification(canBASE_t *node, uint32 messageBox)  
{
    if(node==canREG1)
    {
        canGetData(canREG1, canMESSAGE_BOX2, (uint8 * )&rx_data1[0]); /* copy to RAM */
    }
    if(node==canREG2)
    {
        canGetData(canREG2, canMESSAGE_BOX2, (uint8 * )&rx_data2[0]); /* copy to RAM */
    }
    if(node==canREG3)
    {
        canGetData(canREG3, canMESSAGE_BOX2, (uint8 * )&rx_data3[0]); /* copy to RAM */
    }
    if(node==canREG4)
    {
        canGetData(canREG4, canMESSAGE_BOX2, (uint8 * )&rx_data4[0]); /* copy to RAM */
    }
}

 

This is a little exercise that learns how to configure the CAN peripherals. At the end of the program, the content of the receive buffers should be identical to the transmit info.

 

 

My next exercise will be to send CAN messages physically from one microcontroller to another.

 

Project attached. Have a nice Jack Kilby Day!

The element14 roadtests are a great way to learn new things. Whenever I see a test that interests me, I enroll.

Success is not guaranteed. I've been selected for some, not for others. In this series I'll explain how I decide to enroll or not.

I'll also show how I build my case, including some examples from my applications.

 

This is the technical part of my application for the TI-PMLK Buck Experiment Board: TPS54160 & LM3475

All technical content is here. I haven't removed the part where I'm doing blatant self promotion, because I know no shame.

 

Application: TI-PMLK Buck Experiment Board: TPS54160 & LM3475

 

This Road Test is a very nice fit with the blog series I have here on element14 related to switched mode DC conversion.

I am verifying different converter topologies and technologies and document my findings here on the community.

Although my blogs usually aren't product reviews (they are explanations and experiments) I have the skill, tools and will to verify the educational value of the offer.

 

 

 

My plan is to validate how the educational documentation helps the (to-be) engineer to understand modern switch-mode converters. I would also explain how to validate the characteristics of the design, showing how a typical test setup can detect those characteristics.

I would not investigate the performance of the converter chips themselves. That's something I would do in a road test for that particular IC. The nature of this test looks-and-feels to be focused on showing the kit's educational value.

Here is a selection of switch mode converter blogs that I have posted here on element14:

 

 

GaN Point of Load converter 48V to 1V 50A - part 1: Design Overview
Checking Out GaN Half-Bridge Power Stage: Texas Instruments LMG5200 - Part 1: Preview
Checking Out GaN Half-Bridge Power Stage: Texas Instruments LMG5200 - Part 2: Dead Time Capture
GaN Half-Bridge Power Stage: TI LMG5200 - Part 3: Control Deadband with Hercules LaunchPad
On the TI E2E community: driving GaN with a simple PWM signal
XuLA2 FPGA - PWM with Dead Band in VHDL
The GaN BoosterPack Series: LMG5200 Evaluation Pack and Smart Instrument
Hercules LaunchPad and GaN FETs - Part 1: Control Big Power with a Flimsy Mouse Scroll Wheel
Hercules LaunchPad and GaN FETs - Part 2: Make a BoosterPack
Hercules LaunchPad and GaN FETs - Part 3a: BoosterPack Layout - Reference Design
Hercules LaunchPad and GaN FETs - Part 3b: BoosterPack Layout - my version
Hercules LaunchPad and GaN FETs - Side Note A: BoosterPack Layout - Custom KiCad Parts
Hercules LaunchPad and GaN FETs - Side Note B: Look at the PCB
Low Voltage Step-Down Converter TPS54A20 - First Check
Low Voltage Step-Down Converter TPS54A20 - Series Capacitor

 

 

 

I am also designing an electronic load here on the community, together with fellow member Peter Oakes (we're working on this since last December. Every documentation and all our conversations are public here on the site).

Programmable Electronic Load

This design - using a microcontroller and several ICs from the same supplier - is a natural match for validating the kit.

 

The photo's in the application are taken from the blogs on this community.

 

 

single base scope scan

 

Thanks for considering my application.

Jan.

 

 

Related blog
How I Enroll for a RoadTest - Part 1: yes or no
How I Enroll for a RoadTest - Part 2: success and failure
How I Enroll for a RoadTest - Part 3: Help Me
How I Enroll for a RoadTest - Part 4: Case for Programmable Electronic Load
How I Enroll for a RoadTest - Part 5: Case for Educational Switch Mode Converter Lab

I'm designing a BoosterPack to evaluate GaN devices with the help of a microcontroller.

I've received PCBs from Seeed. Let's have a look ...

 

This is my first Seeed order (a kind element14 community member gave me a rebate coupon that I happily used).

Board specifications:

 

  • PCB Dimension - 10cm Max*10cm Max
  • Layer - 4
  • PCB Thickness - 1.6mm
  • PCB Qty. - 5
  • PCB Color - Green
  • Surface Finish - ENIG
  • Copper Weight - 1oz.
  • Panelized PCBs - 1
  • Expedited Option - NO

 

The price without shipment for this board is 65.12€. Shipping was 7.37€. The coupon got me 9.15€ off ($ 10). Totals to 63.97€

This design requires 2oZ copper layers. My budget can't carry the cost of such a board - so I will not be able to draw full current out of my design.

This is a compromise, one of the many I had to make. I tried to avoid compromises in the design, but did make them when ordering.

Getting a board that has enough copper on it will not require a design change. It's just ticking a different option when ordering and coughing up the monies.

I'd rather do that after I validated that I didn't make mistakes in the PCB layout.

Just like previous designs I did with OSHPark, the Seeed boards look very good at first inspection.

This design is 4 layers, so I have no mechanism to look at the two inner layers. The top and bottom layer look very nice, so that's a good sign.

 

In the images below, the artist renditions on the left side are generated by the Seeed portal.

The photos on the right side are the actual thing. Click on them to get a detailed view.

 

boardtop.pngfront_seeed_pcb.jpg
back_seeed_pcb.jpg

 

 

Populate Order

This is the first time I'll populate a two-sided board. I'll use hot air for the smd components.This is how I plan to approach it:

  1. solder the GaN IC and the inductor. These two have the pins under the device. I'll have to massively bombard them with heat to transfer the energy underneath where the solder paste is.
    I'll use the pre-heater that shabaz gave  me to get the whole board to a close-to-reflow temperature.
  2. then all the smd components on the bottom side. If they fll of later, that's not a big deal, because the are only few.
    I'll also use the pre-heater but on lower temperature, because its heat will be radiating on the inductor and GaN chip.
  3. Then I'll do the remaining top smd components.
    The pre-heater again on a temperature low enough to not desolder the bottom components.
  4. the trough-hole components by hand

 

It is my first time. I'd be happy to take your advice on the preferred order to solder the components.

The tools I have at hand:

  • hot air
  • soldering iron
  • pre-heater

 

edit: I've attached the waveform of one High input pulse as hi01.wfm.

If you have a Rigol DS1052E you can upload that to your scope and examine the ringing with cursors.

 

 

Related Blogs
Hercules LaunchPad and GaN FETs - Part 1: Control Big Power with a Flimsy Mouse Scroll Wheel
Hercules LaunchPad and GaN FETs - Part 2: Make a BoosterPack
Hercules LaunchPad and GaN FETs - Part 3a: BoosterPack Layout - Reference Design
Hercules LaunchPad and GaN FETs - Part 3b: BoosterPack Layout - my version
Hercules LaunchPad and GaN FETs - Side Note A: BoosterPack Layout - Custom KiCad Parts
Hercules LaunchPad and GaN FETs - Side Note B: Look at the PCB
Rotary Encoders - Part 1: Electronics
Checking Out GaN Half-Bridge Power Stage: Texas Instruments LMG5200 - Part 1: Preview
Rotary Encoders - Part 4: Capturing Input on a Texas Instruments Hercules LaunchPad with eQEP
Vintage Turntable repair: Can I fix a Perpetuum Ebner from 1958 - part 4 - Hercules LaunchPad Enhanced PWM try-out

I'm designing a BoosterPack to evaluate GaN devices with the help of a microcontroller.

This double post (a+b) documents the PCB layout, specific for significant currency and high switching frequency.

 

 

Custom Schematic Elements and Footprints Strategy

I rule and live by the law of laziness. I do as little as possible and try to simplify anything that pops up.

That's reflected in my 'custom element creation' strategy: whenever there's a schematic or footprint available, I use it.

Many EEs - and many policies in companies - prefer to create an own footprint for all items used in designs. Not me.

 

Still, in this limited design, I had to create custom items.

For the GaN device and the quadrature encoder there was nothing. I made both symbol and footprint.

For the power connectors and the inductor, I had symbols but no footprints, so I made those.

I've also made a custom footprint for the vias (2 sizes), to have them exactly the same as the TI reference design.

 

The complexity of this exercise was from easy to difficult.

Schematic symbols were all easy. We have low pin counts.

For the footprints, the vias and connectors were easy, the inductor medium, and the LMG5200 and encoder hard. More on that when I describe each item.

All symbols and footprints are available in the attached archive. Each section starts with the filename of the asset in that attachment.

 

LMG5200 GaN IC

symbol LMG5200.lib

footprint lmg5200.pretty.zip

 

 

There's no existing symbol or footprint for the LMG5200 GaN half-bridge.

I used Dave Vandenbout's KiPart script to generate that part (read: copy-paste datasheet info into a spreadsheet and generate symbol from that).

 

LMG5200
typepinnameside
pwr1VINtop
output2HBright
output3HSright
input4HIleft
input5LIleft
pwr6VCCtop
pwr7AGNDbottom
output8SWright
pwr9PGNDbottom

 

See this blog for more info and instructions: Create my first KiCad part with KiPart utility.

The result is the following symbol:

 

To create the footprint of this item, I used the Package Information section of the datasheet.

I used the footprint editor to redraw package, copper and solder mask. There's a little bit of calculations needed to convert all the info in the images to coordinates.

Because the copper pads should blend with the PCB flood filled areas, I've set the pad's footprint to "From parent footprint".

This to avoid that we get thermal reliefs. They are not appropriate for this component (in particular for pins 1, 8 and 9).

 

EVQ-VVD00203B Square SMD Encoder

symbol: rotary_encoders_jan.lib

footprint: Panasonic_Rotary_Encoders.pretty

 

This one also doesn't have footprint or schema symbol. I used the KiCad editor to create the schema. I didn't go fancy.

 

The footprint was tough. The device requires three mounting holes, one of them oval.

 

You set the shape of the drill in the pad preferences.

 

282841-2282841-2Terminal Block 2x1 5.08mm TH

footprint: BuchananTerminalBlocks.pretty

 

 

For this one, I only needed the footprint.

 

This one is straightforward. Nothing special.

 

XAL8080-472ME Inductor, Shielded, Composite, 4.7uH, 10.5A, 8.89 ohm, SMD

footprint: coilcraft_incuctors.pretty

 

 

 

 

 

Again, only the footprint was needed. Just a transform from datasheet measurements to the KiCad footprint editor coordinates.

 

VIAs

footprint: vias.pretty

 

There's not much to be said about these. I made them to stay as close as possible to TI's reference design.

I needed 12 and 38 mil vias for that. Even though KiCad has via footprints, these two values aren't available.

All designs are available in the attached archive. If you are a 3-D artist, I could use your help to create nice KiCad  3-D models of the footprints.

That would make the exercise complete.

 

Related Blogs
Hercules LaunchPad and GaN FETs - Part 1: Control Big Power with a Flimsy Mouse Scroll Wheel
Hercules LaunchPad and GaN FETs - Part 2: Make a BoosterPack
Hercules LaunchPad and GaN FETs - Part 3a: BoosterPack Layout - Reference Design
Hercules LaunchPad and GaN FETs - Part 3b: BoosterPack Layout - my version
Hercules LaunchPad and GaN FETs - Side Note A: BoosterPack Layout - Custom KiCad Parts
Hercules LaunchPad and GaN FETs - Side Note B: Look at the PCB
Rotary Encoders - Part 1: Electronics
Checking Out GaN Half-Bridge Power Stage: Texas Instruments LMG5200 - Part 1: Preview
Rotary Encoders - Part 4: Capturing Input on a Texas Instruments Hercules LaunchPad with eQEP
Vintage Turntable repair: Can I fix a Perpetuum Ebner from 1958 - part 4 - Hercules LaunchPad Enhanced PWM try-out

I'm designing a BoosterPack to evaluate GaN devices with the help of a microcontroller.

board top Seeed

This double post (a+b) documents the PCB layout, specific for significant currency and high switching frequency.

 

 

The Schematic

The EVM User Guide has the schematics for this board. I removed the discrete deadband generator and bias voltage provider.

The deadband generator is replaced by a connection to Hercules LaunchXLII PWM outputs. The bias will come from that same LaunchPad's 5V power.

refschemaannotated.jpg

Here's my version. No bias or deadband circuit.
I've added a quadrature encoder. This part, connected to the Hercules eQEP module, is optional.

 

 

 

The PCB

Except for the changes mentioned above, I tried to stay as close as possible to the TI reference design.

There are several reasons for that:

  • budget: the PCB and GaN devices are expensive. I don't want to have to redo the work (ballpark figure: I loose more than 250 € on PCB and BOM for 3 boards, if I screw up. If you want me to be a hero, then send monies please).
  • I don't have anything close to the proper lab equipment to validate all aspects of the circuit's behaviour.
  • My "high switching frequency, high current" PCB layout skills are mediocre at best.

 

I am a little bit shaken by the cost of a four layer board. If you include shipping, I have a slightly cheaper quote for 3 OSHPark PCBs than for 5 Seeed PCBs with ENIG finish - if you include shipping costs.

A $10 coupon that I kindly got from michaelwylie tipped the balance, so I ordered at Seeed.

 

Here is my layout. You can compare it with TI's reference design images in my previous post.

 

Board Top (copper, mask, silkscreen, forgot to show the drill holes - see the image in the intro section above for those )

White annotations are not part of the PCB design. I've added those on the blog image for clarity (and because jc2048 requested it ).

 

boardtop.png

 

Middle Top layer

 

 

Middle Bottom layer

 

 

 

Board Bottom + copper, mask, silkscreen and drills

 

boardbottom.png

 

I've attached the KiCAD design to this post.

(edit: updated to v 1.1, C30, P2, P3 wrong footprint)

 

In the next post, I'll review the custom schematic and footprint components that I've created for this design - and upload their libs.

 

Related Blogs
Hercules LaunchPad and GaN FETs - Part 1: Control Big Power with a Flimsy Mouse Scroll Wheel
Hercules LaunchPad and GaN FETs - Part 2: Make a BoosterPack
Hercules LaunchPad and GaN FETs - Part 3a: BoosterPack Layout - Reference Design
Hercules LaunchPad and GaN FETs - Part 3b: BoosterPack Layout - my version
Hercules LaunchPad and GaN FETs - Side Note A: BoosterPack Layout - Custom KiCad Parts
Hercules LaunchPad and GaN FETs - Side Note B: Look at the PCB
Rotary Encoders - Part 1: Electronics
Checking Out GaN Half-Bridge Power Stage: Texas Instruments LMG5200 - Part 1: Preview
Rotary Encoders - Part 4: Capturing Input on a Texas Instruments Hercules LaunchPad with eQEP
Vintage Turntable repair: Can I fix a Perpetuum Ebner from 1958 - part 4 - Hercules LaunchPad Enhanced PWM try-out

 

I'm designing a BoosterPack to evaluate GaN devices with the help of a microcontroller.            

This post documents the PCB layout, specific for significant currency and high switching frequency.

 

The GaN Evaluation BoosterPack - Computer Controlled version of the Reference Design

The GaN BoosterPack that I'm designing is a close brother to TI's LMG5200 reference design. The power electronics part is - deliberate - identical to the reference.

The purpose of the circuit is to have an evaluation tool where you can check GaN FET behaviour under varying conditions.

So I left all GaN power related parts as-is, and replaced the input control logic.

The reference design uses RC circuits to generate the required input signals. The user controls frequency and duty cycle of that input circuit by providing an external PWM signal.

Other parameters, such as the deadband and the duty cycle ratio between different driver signals are preset.  You can change them by modifying the discrete components on the reference design (read: desoldering and replacing SMD caps and/or resistors).

 

I'm modding the design so that it takes the deadband from an external source. In my case, that source is a Hercules LaunchPad that runs an SCPI interpreter and can be controlled by LabVIEW.

 

The Gerbers for the reference designs are available from TI's website. If you load all the Gerber files into KiCAD's Gerber viewer, here are the ones you have to activate to get a good look-and-feel of the design:

  • 1 midlayer 1  G1 (upper midlayer)
  • 2 bottom layer GBL
  • 6 drill layer GD1
  • 7 drill guideline GG1
  • 23 interpanel GP1 (lower midlayer)
  • 26 top layer GTL
  • 3 bottom overlay GBO
  • 27 top overlay GTO

 

{gallery} TI Reference Design

Upper Mid Layer

1 midlayer 1  G1 (upper midlayer)

2 bottom layer GBL

2 bottom layer GBL

interpanel GP1 (lower midlayer)

23 interpanel GP1 (lower midlayer)

top layer GTL

26 top layer GTL

drill layer GD1

6 drill layer GD1

drill guideline GG1

7 drill guideline GG1

bottom overlay GBO

3 bottom overlay GBO

top overlay GTO

27 top overlay GTO

Layer Stack Up

 

 

The Layout Application Note

TI has an elaborate  guide with 'Layout Considerations for LMG5200 GaN Power Stage'. This document contains theory and practice on how to layout 2 or 4 layer PCBs for this device.

This goes well together with the EVM kit that I'm copy-catting here. The PCB of the EVM is used as the practical realisation of the layout theories and guidelines.

That means that I have all that's needed for my work: explanation, a physical example (TI gave me an EVM) and the Gerber files. Over to KiCad and draw my own version...

 

 

 

In the next post I'll post the schematics and PCB layout - and the KiCAD sources.

(was planning to do that now, but I can't upload images to the blog since this afternoon...)

 

Related Blogs
Hercules LaunchPad and GaN FETs - Part 1: Control Big Power with a Flimsy Mouse Scroll Wheel
Hercules LaunchPad and GaN FETs - Part 2: Make a BoosterPack
Hercules LaunchPad and GaN FETs - Part 3a: BoosterPack Layout - Reference Design
Hercules LaunchPad and GaN FETs - Part 3b: BoosterPack Layout - my version
Hercules LaunchPad and GaN FETs - Side Note A: BoosterPack Layout - Custom KiCad Parts
Hercules LaunchPad and GaN FETs - Side Note B: Look at the PCB
Rotary Encoders - Part 1: Electronics
Checking Out GaN Half-Bridge Power Stage: Texas Instruments LMG5200 - Part 1: Preview
Rotary Encoders - Part 4: Capturing Input on a Texas Instruments Hercules LaunchPad with eQEP
Vintage Turntable repair: Can I fix a Perpetuum Ebner from 1958 - part 4 - Hercules LaunchPad Enhanced PWM try-out
For a hardware evaluation project I'm working on, I want to create a device that can be controlled via LabVIEW.
LabVIEW can talk to instruments using serial out of the box, and it knows how to talk Standard Commands for Programmable Instruments (SCPI).

 

 

In this blog I adapt the LabVIEW Virtual Instrument and the firmware to give direct access to the Hercules PWM Time base control registers.

You'll be able to independently set all 7 PWM modules that are available on the controller.

 

 

The FirmWare Support for Direct Register Access

I provided a SCPI command that can receive a numeric value from LabVIEW and write that to the correct PWM module.

Here's the pattern:

    {.pattern = "PWM#:TBCTL", .callback = SCPI_HerculesPwmTBCTL,},

 

The implementation is very simple. Just like in the previous blog, we'll retrieve the PWM module, and the register value, from the SCPI command we get from LabVIEW.

LabView will send something like this:

PWM2:TBCTL #H200

 

We'll have to derive from this string that the PWM register set we have to address is that of PWM module 2.

And we'll have to write 0x0200 into its TBCTL register.

 

I have refactored my code since the first blog, to separate the Hercules PWM details from the SCPI parser. And I've factored out some functionality that can be reused accross many functions.

The code to get the right PWM module has gotten its own function:

 

static scpi_result_t PwmGetModule(scpi_t *context, uint32_t *uModule) {
  int32_t numbers[1];

  // retrieve the PWM channel. Can be 1 - 7
  SCPI_CommandNumbers(context, numbers, 1, 1);
  if (! ((numbers[0] > 0) && (numbers[0] < 8) )) {
  // todo push error on stack if the PWM CHANNEL not between 1 and 7
  return SCPI_RES_ERR;
  } else {
  *uModule = numbers[0];
  return SCPI_RES_OK;
  }
}

 

And here's the code that parses ut the register value and sends all to the Hercules PWM side:

/**
 * Set PWM register TBCTL
 *
 * Return SCPI_RES_OK
 *
 */
static scpi_result_t SCPI_HerculesPwmTBCTL(scpi_t * context) {

    int32_t param1;
    uint32_t uModule;
    if (PwmGetModule(context, &uModule) == SCPI_RES_ERR) {
        return SCPI_RES_ERR;
    }

     /* read first parameter if present */
     if (!SCPI_ParamInt32(context, &param1, TRUE)) {
         return SCPI_RES_ERR;
     }
     pwmTBCTL(uModule, param1);

    return SCPI_RES_OK;
}

 

In that PWM part, I simply write the value to the relevant register of the correct module:

// array of the 7 PWM registers of the RM46
etpwmBASE_t *pwmRegs[7] ={etpwmREG1, etpwmREG2, etpwmREG3, etpwmREG4, etpwmREG5, etpwmREG6, etpwmREG7} ;

void pwmTBCTL(uint32_t uModule, uint16_t uValue) {
  pwmRegs[uModule-1] -> TBCTL = uValue;
}

 

TBCTL is a 16 bit register that drives the following PWM behaviour (and more, that I don't discuss here):

Bit 9 - 7 are the high speed clock divider bits. A few examples

0b111: /14

0b001: /2

0b000: /1

 

Bit 1 - 0 indicate the counter mode. We'll use these two in our example:

0b00: normal up count

0b11: freeze counter

 

That's why you'll see the following useful Hex codes on the LabVIEW display below:

PWM 1 MHz: 0

PWM 500 kHz: 80

PWM 125 kHz: 200

PWM of: 3

 

This register isn't the one where you will later define the exact frequencies. I'll provide additional SCPI functionality to talk to those.

But for the things we want to show here - that we can select to what module we talk, and can push data to a register - TBCTL  will do just fine.

 

The LabVIEW Design

This version of the LabVIEW panel has two user editable controls.

There's a dial that allows you to select PWM module 1 to 7.

 

When you run the LabVIEW process, it will talk to that PWM module of your Hercules LaunchPad.

 

The second control is an edit box where you can type the hexadecimal value of what you want to write to that PWM module's TBCTL  register.

For convenience, I've added a table with some useful values next to it.

Use this edit box together with your controller's technical reference manual.

The LabVIEW program here is a great tool for you to better learn your controller's PWM module.

You can type in any value you like (better base it on the instructions in the TRM ), and beam them directly into the register.

You can attach a scope and see the results.

 

Here's the very simple LabVIEW block diagram.

The string constant holds the following value:

PWM%u:TBCTL\s#H%s\n

 

That is sent into a Format Into String block, together with the values of the dial and the edit control.

At the output of the block, you'll get:

PWM2:TBCTL #H80\n

 

That is sent off to the Hercules LaunchPad over USB.

 

The results

Let's see how the outputs of PWM module 1 and 2 look lik when we send a few commands.

 

After sending 0x3 to both modules (both off):

 

After sending 0x80 to PWM 2 (500kHz):

 

After sending 0x0 to PWM 1 (1MHz):

 

 

It's easier to understand why 0x03 switches off the PWM signal and why the other magical HEX values do what they do if you know the layout of the register we're addressing. Here are the relevant bits explained.

Source:  http://www.ti.com/lit/pdf/spnu514

 

 

The source for LabVIEW and the Hercules CCS project are attached to this blog.

You can try this yourself.

 

 

Related Blog

Create a Programmable Instrument with SCPI - Part 1: Parser Library
Create a Programmable Instrument with SCPI - Part 2: Serial over USB
Create a Programmable Instrument with SCPI - Part 3: First Conversation *IDN?
Create a Programmable Instrument with SCPI - Part 4: Error Handling by Default
Create a Programmable Instrument with SCPI - Part 5: First Hardware Commands
Create a Programmable Instrument with SCPI - Part 6: LabVIEW Integration
Create a Programmable Instrument with SCPI - Part 7: Talk to Hardware Registers
For a hardware evaluation project I'm working on, I want to create a device that can be controlled via LabVIEW.
LabVIEW can talk to instruments using serial out of the box, and it knows how to talk Standard Commands for Programmable Instruments (SCPI).

 

 

In this blog I make a LabVIEW Virtual Instrument that turns PWM signals on and off.

 

 

LabVIEW Design

We'll create a LabVIEW control panel that can toggle PWM output of a Hercules microcontroller.

In the previous blogs we enabled our Hercules LaunchPad USB and made firmware that knows how to interpret SCPI.

Our LabVIEW program has to be able to connect to our USB port and send SCPI commands.

We'll use a toggle button to switch PWM on and off.

 

Requirements of the LabVIEW design:

  • connect to a COM port and talk serial
  • Send the right SCPI commands to the COM port, depending on the position of the toggle switch.

 

There's an example program in LabVIEW that gets us 70% of what we need: examples\Instrument IO\Serial\Simple Serial.vi.

That one can connect to our LaunchPad over USB and send the SCPI command *IDN? (we've used this program earlier on in our tests).

We can use the complete program - we just need to replace the constant string '*IDN?' with either PWM1:STATe ON or PWM1:STATe OFF depending on the state of our toggle switch.

 

That isn't hard. The first thing we do is place a boolean control on our canvas. I selected a switch that gives a good indication of On/Off. I named it PWM.

 

Then, in the Block Diagram,I added a Case block, and wired the switch to that.

I also added two constant string items, one containing PWM1:STATe ON,the other PWM1:STATe OFF.

I wired the two strings to the case statement as inputs. The output of the case statement is routed to where the original *IDN? data was flowing.

 

 

 

In the case block, for the False state, I routed the OFF input to the output. For the True state, I routed the ON input. And that's it.

To test the program, set the toggle in the desired position and run your LabVIEW program.

The PWM output will switch on or off based on that.

 

 

I've attached the LabVIEW project to this blog. The firmware for the Hercules LaunchPad is available in the previous one.

Give it a try!

 

Related Blog

Create a Programmable Instrument with SCPI - Part 1: Parser Library
Create a Programmable Instrument with SCPI - Part 2: Serial over USB
Create a Programmable Instrument with SCPI - Part 3: First Conversation *IDN?
Create a Programmable Instrument with SCPI - Part 4: Error Handling by Default
Create a Programmable Instrument with SCPI - Part 5: First Hardware Commands
Create a Programmable Instrument with SCPI - Part 6: LabVIEW Integration
Create a Programmable Instrument with SCPI - Part 7: Talk to Hardware Registers
For a hardware evaluation project I'm working on, I want to create a device that can be controlled via LabVIEW.
LabVIEW can talk to instruments using serial out of the box, and it knows how to talk Standard Commands for Programmable Instruments (SCPI).

 

scpi PWM On

 

In this blog I build the first hardware command to turn PWM signals on and off.

 

 

One Function Handles 7 PWM Modules

The first command isn't the easiest one. We'll build a function that can talk to any of 7 available PWM modules of the Hercules controller.

SCPI has a construct that allows you to provide a wildcard in the command. That wildcard can be replaced by a number when calling the command from LabVIEW.

 

    {.pattern = "PWM#:STATe", .callback = SCPI_HerculesPwmState,},

 

When you shoot a command where the # is substituded by a number  (i.e.: PWM1:STATe ON), the SCPI_HerculesPwmState() function gets called.

The substituted number is available in that function by calling the API SCPI_CommandNumbers().

With that number, I retrieve the correct PWM hardware register and switch the signal on or off.

 

PWM on off via USB

 

These are the SCPI test calls:

PWM1:STATe ON
PWM1:STATe OFF

 

This is the function that gets called. Don't worry about the magical numbers that are assigned to the PWM register. I'll improve the code while I design the firmware.

param1 holds true if you pass ON or 1 in SCPI command. false if you give OFF or 0.

 

// array of the 7 PWM registers of the Hercules RM46 controller
etpwmBASE_t *pwmRegs[7] ={etpwmREG1, etpwmREG2, etpwmREG3, etpwmREG4, etpwmREG5, etpwmREG6, etpwmREG7} ;

static scpi_result_t SCPI_HerculesPwmState(scpi_t * context) {

    int32_t numbers[1];
    scpi_bool_t param1;
    etpwmBASE_t *pwmReg = NULL;

    // retrieve the PWM channel. Can be 1 - 7
    SCPI_CommandNumbers(context, numbers, 1, 1);

    // todo error if the PWM CHANNEL not between 0 and 7.
    // code below will fail because we'll read invalid memory locations
    pwmReg = pwmRegs[numbers[0]-1];

     /* read first parameter if present */
     if (!SCPI_ParamBool(context, &param1, TRUE)) {
         return SCPI_RES_ERR;
     }
     if (param1) { // switch PWM on
         pwmReg -> TBCTL = ETPWM1_TBCTL_CONFIGVALUE;
     } else { // switch PWM off
         pwmReg -> TBCTL = 131;
     }

    return SCPI_RES_OK;
}

 

That substitution is a powerful construct. With little effort I can control multiple similar modules.

The SCPI library has all the logic that's needed to support this. I just have to use it properly.

Once more it didn't take a lot of code to build flexible functionality.

 

I've attached the CCS project to this blog.

Compile, load to your RM46 LaunchPad and connect with a serial terminal program using 9600, 8, 2, N

 

Put an oscilloscope probe on J11 16 and 18. You'll find two complementary 1MHz PWM signals.

Submit these commands in putty to switch them off and back on:

 

 

 

PWM1:STATe OFF
PWM1:STATe ON

 

In the next blog I'll attach a LabVIEW example that switches the signals.

 

Related Blog

Create a Programmable Instrument with SCPI - Part 1: Parser Library
Create a Programmable Instrument with SCPI - Part 2: Serial over USB
Create a Programmable Instrument with SCPI - Part 3: First Conversation *IDN?
Create a Programmable Instrument with SCPI - Part 4: Error Handling by Default
Create a Programmable Instrument with SCPI - Part 5: First Hardware Commands
Create a Programmable Instrument with SCPI - Part 6: LabVIEW Integration
Create a Programmable Instrument with SCPI - Part 7: Talk to Hardware Registers
For a hardware evaluation project I'm working on, I want to create a device that can be controlled via LabView.
LabView can talk to instruments using serial out of the box, and it knows how to talk Standard Commands for Programmable Instruments (SCPI).

 

 

In this blog I'm checking the excellent error handling of the SCPI library.

 

 

Error Handling Works by Default

The SCPI parser library that I use has out-of-box support for standard behaviour. One of the supported features is error handling.

If you send a bogus SCPI command or make a syntax error, this is registered by the library.

The error description is pushed on an error stack. The parser returns to its normal work.

As an instrument firmware designer, you can also push custom error situations to the error stack.

A possible use case is for a PWM generator where the user requests a frequency higher than the maximum.

 

You can check if errors occurred by sending the SCPI command:

SYST:ERR:COUN?

 

If errors happened, you get a number back. That's the count of errors on the stack.

e.g.:

5

 

Each error can be retrieved by firing:

SYST:ERR?

 

A possible return value (one of the default error messages from our parser lib):

-113,"Undefined header"

 

Each time you ask an error message, the error is popped off the stack and the error count decreases.

When you've retrieved the last message, you get the following reply when shooting a  SYST:ERR:COUN? :

0

 

If you check for an error message when the error stack is empty, (SYST:ERR?), you get:

0,"No error"

 

You get all this functionality by default and you can tap into it in your own firmware. Another worry taken out of your hands by this library.

Other standard constructs that are either fully supported, or give you an easy implementation hook are:

 

    { .pattern = "*CLS", .callback = SCPI_CoreCls,},
    { .pattern = "*ESE", .callback = SCPI_CoreEse,},
    { .pattern = "*ESE?", .callback = SCPI_CoreEseQ,},
    { .pattern = "*ESR?", .callback = SCPI_CoreEsrQ,},
    { .pattern = "*IDN?", .callback = SCPI_CoreIdnQ,},
    { .pattern = "*OPC", .callback = SCPI_CoreOpc,},
    { .pattern = "*OPC?", .callback = SCPI_CoreOpcQ,},
    { .pattern = "*RST", .callback = SCPI_CoreRst,},
    { .pattern = "*SRE", .callback = SCPI_CoreSre,},
    { .pattern = "*SRE?", .callback = SCPI_CoreSreQ,},
    { .pattern = "*STB?", .callback = SCPI_CoreStbQ,},
    { .pattern = "*TST?", .callback = SCPI_CoreTstQ,},
    { .pattern = "*WAI", .callback = SCPI_CoreWai,},

 

 

Test with PuTTY

 

When you want to test special conditions, it's often easier to use a terminal program than LabVIEW. You can just type away, and the results arrive in the parser lib immediately.

 

When I try to simulate a real test environment, I mock it with LabVIEW. But when I try to exercise a particular part of the library, or want to see how my firmware reacts on each single character (valid or invalid), plain old PuTTY is easier.

 

PuTTY is also easy to learn the SCPI parser lib. Set a breakpoint in the SCPI_Input() function and type *IDN?<enter> in PuTTY. Your code breaks at each character you type. You can step trough the logic that builds up the command string. You'll also see how the library recognises when it received a full command.

You can then step trough the execution of the code that implements that command.

If you do that a few times, you'll get a deep understanding of the library. It 'll help you to extend it in the right way.

 

Related Blog

Create a Programmable Instrument with SCPI - Part 1: Parser Library
Create a Programmable Instrument with SCPI - Part 2: Serial over USB
Create a Programmable Instrument with SCPI - Part 3: First Conversation *IDN?
Create a Programmable Instrument with SCPI - Part 4: Error Handling by Default
Create a Programmable Instrument with SCPI - Part 5: First Hardware Commands
Create a Programmable Instrument with SCPI - Part 6: LabVIEW Integration
Create a Programmable Instrument with SCPI - Part 7: Talk to Hardware Registers
For a hardware evaluation project I'm working on, I want to create a device that can be controlled via LabView.
LabView can talk to instruments using serial out of the box, and it knows how to talk Standard Commands for Programmable Instruments (SCPI).

 

1stparse.png

 

In this blog I have a working SCPI conversation between LabVIEW and a Hercules safety microcontroller.

 

 

SCPI Parser LIB Learns to Reply via USB

In the previous blog, I stopped when LabVIEW and the microcontroller were able to perform a mock conversation over USB.

LabVIEW sent us an *IDN? command, and the Hercules just echoed that command back to LabVIEW.

 

For a meaningful conversation, we have to do three things:

  • send the command string we received from LabVIEW to the SCPI parser library
  • inform the parser library how and what it should reply on an *IDN? command.
  • learn the library how to reply via our USB port

 

 

Sending the string to the library is done for each character, as soon as we've received it. I'm using a freeRTOS interrupt notification mechanism.

 

freertos interrupt handler and lock metaphor

 

I have an RTOS task that sits ready forever to consume characters from the USB port. It doesn't run.

In the Read interrupt handler for my serial comms module, I have put a 'wake-up' call. It notifies the halted task that it can continue.

 

The halted task proceeds, moves the character to the parser input, and goes back to sleep until the next interrupt (the next character).

 

That's a step up from my initial design, where I was sleeping and polling for input.

 

 

Initially I implemented a buffer to compose a string from the input characters, and send that concatenated string to the parser. But the parser has its own buffer mechanism.

I've changed my code to send each character to the lib directly. Whenever it determines that it received a complete command,it sends the reply via USB.

If this approach turns out to be too naive or too costly, I'll revert to buffering the data before sending it.

As explained in the side note above, the function normally halts at ulTaskNotifyTake(), waiting to be woken up by the USB Read interrupt.

 

void prvUARTCommandConsoleTask(void *pvParameters) {
    (void) pvParameters;
    _uRxChar = 0U;
    scpi_instrument_init();
    sciReceive(scilinREG, 1, (uint8 *)&_uRxChar);

    for( ;; ) {
        /* Block indefinitely (without a timeout, so no need to check the function's
            return value) to wait for a notification.  Here the RTOS task notification
            is being used as a binary semaphore, so the notification value is cleared
            to zero on exit.  NOTE!  Real applications should not block indefinitely,
            but instead time out occasionally in order to handle error conditions
            that may prevent the interrupt from sending any more notifications. */
        ulTaskNotifyTake( pdTRUE,          /* Clear the notification value before
                                               exiting. */
                portMAX_DELAY ); /* Block indefinitely. */

        /* The RTOS task notification is used as a binary (as opposed to a
            counting) semaphore, so only go back to wait for further notifications
            when all events pending in the peripheral have been processed. */

        // in my case: I get an interrupt for a single character, no need to loop.

         scpi_instrument_input((const char *)&_uRxChar, 1);

        sciReceive(scilinREG, 1, (uint8 *)&_uRxChar);
    }
}

 

The USB Read interrupt service routine just unlocks that task by sending it a notification vTaskNotifyGiveFromISR().

 

#pragma WEAK(sciNotification)
void sciNotification(sciBASE_t *sci, uint32 flags)     
{
/*  enter user code between the USER CODE BEGIN and USER CODE END. */
/* USER CODE BEGIN (29) */
    if ((flags == SCI_RX_INT) && (sci == scilinREG)) {
        BaseType_t xHigherPriorityTaskWoken;
        /* xHigherPriorityTaskWoken must be initialised to pdFALSE.  If calling
            vTaskNotifyGiveFromISR() unblocks the handling task, and the priority of
            the handling task is higher than the priority of the currently running task,
            then xHigherPriorityTaskWoken will automatically get set to pdTRUE. */
        xHigherPriorityTaskWoken = pdFALSE;


        /* Unblock the handling task so the task can perform any processing necessitated
            by the interrupt.  xHandlingTask is the task's handle, which was obtained
            when the task was created. */
        vTaskNotifyGiveFromISR( xUARTCommandInterpreterTaskHandle, &xHigherPriorityTaskWoken );


        /* Force a context switch if xHigherPriorityTaskWoken is now set to pdTRUE.
            The macro used to do this is dependent on the port and may be called
            portEND_SWITCHING_ISR. */
        portYIELD_FROM_ISR( xHigherPriorityTaskWoken );        // empty by design
    }
/* USER CODE END */
}

 

 

The reply for the *IDN? command has to be placed in the application specific context that we pass to the library at initialisation time.

 

#define SCPI_IDN1 "TEXASINSTRUMENTS"
#define SCPI_IDN2 "LAUNCHXL2-RM46"
#define SCPI_IDN3 NULL
#define SCPI_IDN4 "001000"

// ...

void scpi_instrument_init() {
     SCPI_Init(&scpi_context,
             scpi_commands,
             &scpi_interface,
             scpi_units_def,
             SCPI_IDN1, SCPI_IDN2, SCPI_IDN3, SCPI_IDN4,
             scpi_input_buffer, SCPI_INPUT_BUFFER_LENGTH,
             scpi_error_queue_data, SCPI_ERROR_QUEUE_SIZE);

 

You tell the SCPI library how to reply over USB by implementing the function SCPI_Write().

In the example that comes with the lib, the results are written to stdout. In our embedded app, it'll have to go to the serial communications API.

 

size_t SCPI_Write(scpi_t * context, const char * data, size_t len) {
    (void) context;
    sciSend(scilinREG, len, (uint8 *)data);
    return len;
}

 

If you don't have LabVIEW, don't worry.

You can use PuTTY (or another terminal program) to run SCPI over USB.

Here's the result of running the *IDN? command, while connected at 9600, 8, 2, N:

 

You won't see the commands you type, because SCPI doesn't echo them back.

A simple trick is to temporarily turn on local echo in PuTTY, so you see your input while you type it.

Don't get confused by that 'local echo' edit mode: even though it seems you can correct your entry while typing, that's not true.

All characters are directly sent to the USB port as you type them. And there's no error handling (yet) on the controller side.

 

 

 

Further Steps

And that's it. By adding these three things to the puzzle, I can have a first meaningful conversation between LabVIEW and my own instrument.

Step by step, I can now add instrument functionality.

The first thing I want to do is control the PWM module. I'll provide functions to set and read PWM period, duty cycle and dead time.

That will be the first time that I can change behaviour of my instrument via LabVIEW.

 

The CCS project is attached to this blog. It includes the HALCoGen settings, the SCPI lib and all firmware.

It's set up for a RM46 microcontroller with freeRTOS. With the info from the two previous blog posts, it isn't difficult to port it to another Hercules controller.

 

Related Blog

Create a Programmable Instrument with SCPI - Part 1: Parser Library
Create a Programmable Instrument with SCPI - Part 2: Serial over USB
Create a Programmable Instrument with SCPI - Part 3: First Conversation *IDN?
Create a Programmable Instrument with SCPI - Part 4: Error Handling by Default
Create a Programmable Instrument with SCPI - Part 5: First Hardware Commands
Create a Programmable Instrument with SCPI - Part 6: LabVIEW Integration
Create a Programmable Instrument with SCPI - Part 7: Talk to Hardware Registers
For a hardware evaluation project I'm working on, I want to create a device that can be controlled via LabView.
LabView can talk to instruments using serial out of the box, and it knows how to talk Standard Commands for Programmable Instruments (SCPI).

 

usb port configuration in HALCoGen

 

In this blog I'm writing the serial communication firmware for a Hercules safety microcontroller.

 

 

SCPI Physical Communications Link is Undefined

SCPI does not care how you connect your two systems. That's what wikipedia says about SCPI - and it's true. You'll find instruments that can talk SCPI over TCP/IP, a GPIB interface, a serial port or via USB.

The heart of my test device is a Hercules RM46 LaunchPad. It has a USB connector that's bridged with one of the Hercules' serial communication modules.

 

On the PC, this USB is available as a COM port (UART).

Good enough for LabVIEW - it supports serial communication out of box.

 

 

Design Decisions for Serial Comms

Listening for LabVIEW commands isn't the only thing the test instrument will have to do. The SCPI interface is only one of its functionalities.

That means that we can't just sit there and wait for data to arrive on the serial comms interface. We'll have to use another strategy.

 

I'm using a real-time operating system (freeRTOS) as the basis for the firmware. That will make my work to look after multiple functionalities simpler.

 

I'll have a task that picks up any data sent over the USB and sends the info to the SCPI parser. But that task is not going to read from the USB.

To handle the part of fetching data and bringing it into the application scope, I'm setting up a Read interrupt.

The Hercules driver for SCI automatically runs in background mode when you do that (i.e.: the sciRead() function of that API returns immediately without reading the data - it just prepares the receive buffer).

Once the read interrupt fires, the data is ready.

Because the length of the SCPI commands are variable, I'm reading one character at a time and start processing the info when I receive a terminator character.

 

Configure the RTOS and the Serial Communication Driver

You configure Hercules microcontrollers with HALCogen. The tool will do four tasks for us.

  • create source code for the freeRTOS Hercules port
  • generate initialisation code for the peripherals - the serial communications module in this case
  • configure clock, memory, interrupts
  • generate source code for the device APIs - again for the serial comms module in this design.

 

 

HALCoGen is a round-trip configurator. You can safely switch between the tool and your source - both directions.

 

The first task is to opt for an RTOS project.

You do that when you create your project.

Select the correct controller, and opt for the FREERTOS entry.

 

 

You can set RTOS specific settings in a dedicated configuration pane.

 

That's it for the RTOS.

Later, when we ask HALCoGen to generate our project code, it will create the Hercules port sources and will put these configuration settings in the relevant freeRTOS config files.

 

Next, we configure the serial communications device.

When you enable the driver, HALCoGen will create driver API source code.

 

 

Then you set the parameters. These will end up in the API's initialisation function.

I flag that I want to use the Read interrupt.

 

 

The baud rate is set to 9600, with 8,2,N (LabVIEW will have to use the same settings when talking to our instrument)

 

The last thing we have to do is enable the interrupt handler for the serial comms module.

Because we've configured High Level interrupt on the module page, we'll have to enable the corresponding high level interrupt in the vector.

 

 

HALCoGen can now generate our project sources. Over to the IDE.

 

Firmware

Because we use an RTOS, our main() is almost empty.

The first part calls the serial comms API init function to apply the settings we've done in HALCoGen.

Then we enable the interrupts.

The Read interrupt will fire from the moment we get data on the serial port.

 

The second part of main() registers our RTOS tasks and starts the engine.

 

void main(void)
{
/* USER CODE BEGIN (3) */
    sciInit();
    _enable_IRQ();

    // Register the command interpreter
    vStartUARTCommandInterpreterTask();

    // start RTOS
    vTaskStartScheduler();
    while(1);
/* USER CODE END */
}

 

We don't have to do anything in the serial communications interrupt handler (for now at least. We add functionality in the next blog post).

Just by defining that we want to use a read trigger, the API knows how to behave.

 

If you disable the read trigger, the serial comms API will run in blocking mode.

if you call sciRead(size),  the function will wait until you receive size bytes, and then return. The SCI buffer will contain the bytes read.

 

If you enable the read trigger, the API runs in non-blocking mode.

If you call sciRead(size),  the function prepares the buffer and trigger, and immediately returns. Your program can proceed with other things.

When you receive size bytes, the trigger fires (and you can act on that if you want) and in parallel the data is available in the SCI buffer.

 

 

In my firmware, I have an RTOS job that will pick up any character received, and that re-builds a SCPI command string from them.

Once the string is complete (when we receive a 0x0A character), we send it to the SCPI parser API, and return the result to LabVIEW.

... or, that's what will happen in the future. At this moment I just echo the string back, as a proof of concept.

 

 

void prvUARTCommandConsoleTask(void *pvParameters) {

    ( void ) pvParameters;
    _uRxChar = 0U;
    uint32_t i = 0L;

    sciReceive(scilinREG, 1, (uint8 *)&_uRxChar);

    for( ;; )
    {
        /* Only interested in reading one character at a time. */
        if (_uRxChar) {
            _uCommandBuffer[i] = _uRxChar;
            i++; // todo this must be controlled, reset the buffer after a command is finished or error when overrunning
            if (_uRxChar == 0x0A) {
                // we have a command. Send it to the parser queue
                // test implementation: echo
                sciSend(scilinREG, i, _uCommandBuffer); // todo remove this.

                i = 0U;
            }
            _uRxChar = 0U;
            sciReceive(scilinREG, 1, (uint8 *)&_uRxChar);
        }
    }
}

 

Test in LabVIEW

There's an example (Simple Serial) that sends the *IDN? command to a serial device, and shows the reply it receives from that device.

That's an excellent test bed candidate.

 

I need to set the serial parameters correctly. My Hercules LaunchPad USB is registered as COM4.

In HALCoGen, I had set up the serial parameters as 9600, 8, 2, N.

When I run the Simple Serial example, the SCPI command *IDN? is sent to COM4, and half a second later LabVIEW tries to read the reply.

Because my test firmware just sends the command back that it received, the program should show *IDN? in the result pane.

It should also show a data count of 6 (5 characters + the closing character 0x0A are all sent back).

 

 

Related Blog

Create a Programmable Instrument with SCPI - Part 1: Parser Library
Create a Programmable Instrument with SCPI - Part 2: Serial over USB
Create a Programmable Instrument with SCPI - Part 3: First Conversation *IDN?
Create a Programmable Instrument with SCPI - Part 4: Error Handling by Default
Create a Programmable Instrument with SCPI - Part 5: First Hardware Commands
Create a Programmable Instrument with SCPI - Part 6: LabVIEW Integration
Create a Programmable Instrument with SCPI - Part 7: Talk to Hardware Registers
For a hardware evaluation project I'm working on, I want to create a device that can be controlled via LabVIEW.
LabVIEW can talk to instruments using serial out of the box, and it knows how to talk Standard Commands for Programmable Instruments (SCPI).

 

 

In this blog I'm trying out the SCPI parser library of Jan Breuer.

 

 

SCPI

Standard Commands for Programmable Instruments (SCPI) is an IEEE standard for communicating with instruments.

It defines how a dialog between machines works. Like many communication languages it defines the request-reply syntax and the structure of commands and data.

A typical command that all instruments should support is the *IDN? (identity) command.

The test instrument replies with its identity. For a Rigol DS1102E oscilloscope, you'd get a reply  that looks like this: RIGOL TECHNOLOGIES,DS1102E,DS1EB104702974,00.02.01.01.00.

Other commands typically set the instrument in a certain status, change a parameter, query configuration settings or exchange data.

 

Because the language is standardised, there are some instrument side libraries that implement SCPI. They parse SCPI commands and help firmware developers to reply in the correct way..

I'm checking out Jan Breuer's SCPI parser library (available on github). If I manage to understand his library, I'll use it. And that's the exercise for now - getting to know the lib.

 

At the end of this blog series, we have a smart instrument that can control 7 PWM modules independently.

Each module will be able to generate two in-sync or complementary signals,

 

LabVIEW smart Hercules PWM generator

 

The duty cycle of each signal is separately configurable. Also the deadband is separately changeable for each signal.

 

Getting to know the SCPI Parser Library

My instrument will have an ARM microcontroller. But I'm first testing the library on a Windows PC.

I'm running trough the example programs to see how the commands are interpreted. My favourite learning method is stepping trough the code with a debugger.

 

Here's a snippet of the test-parser example.

 

    TEST_SCPI_INPUT("*IDN?\r\n");
    TEST_SCPI_INPUT("SYST:VERS?");
    TEST_SCPI_INPUT("\r\n*ID");
    TEST_SCPI_INPUT("N?");
    TEST_SCPI_INPUT(""); /* emulate command timeout */


    TEST_SCPI_INPUT("*ESE\r\n"); /* cause error -109, missing parameter */
    TEST_SCPI_INPUT("*ESE #H20\r\n");

 

 

The TEST_SCPI_INPUT() macro is a wrapper around the lib's parser function

 

#define TEST_SCPI_INPUT(cmd)    result = SCPI_Input(&scpi_context, cmd, strlen(cmd))

 

In the examples, the "device under test" is - typical for unit tests - a mock implementation in software.

For the *IDN? command, it should return a concatenation of the following strings:

 

#define SCPI_IDN1 "MANUFACTURE"
#define SCPI_IDN2 "INSTR2013"
#define SCPI_IDN3 NULL
#define SCPI_IDN4 "01-02"

 

In my firmware, I'll have to provide the relevant values for my instrument.

 

The parser expects a callback function for each of the commands you support. In the mock implementation, Jan pretends that the instrument is a digital multimeter.

 

    {.pattern = "MEASure:VOLTage:DC?", .callback = DMM_MeasureVoltageDcQ,},
    {.pattern = "CONFigure:VOLTage:DC", .callback = DMM_ConfigureVoltageDc,},
    {.pattern = "MEASure:VOLTage:DC:RATio?", .callback = SCPI_StubQ,},
    {.pattern = "MEASure:VOLTage:AC?", .callback = DMM_MeasureVoltageAcQ,},
    {.pattern = "MEASure:CURRent:DC?", .callback = SCPI_StubQ,},
    {.pattern = "MEASure:CURRent:AC?", .callback = SCPI_StubQ,},
    {.pattern = "MEASure:RESistance?", .callback = SCPI_StubQ,},
    {.pattern = "MEASure:FRESistance?", .callback = SCPI_StubQ,},
    {.pattern = "MEASure:FREQuency?", .callback = SCPI_StubQ,},
    {.pattern = "MEASure:PERiod?", .callback = SCPI_StubQ,},

 

 

You can see handlers for MEASure requests and for CONFigure requests.

Here's the mock implementation that handles measuring DC voltage:

 

static scpi_result_t DMM_MeasureVoltageDcQ(scpi_t * context) {
    scpi_number_t param1, param2;
    char bf[15];
    fprintf(stderr, "meas:volt:dc\r\n"); /* debug command name */

    /* read first parameter if present */
    if (!SCPI_ParamNumber(context, scpi_special_numbers_def, &param1, FALSE)) {
        /* do something, if parameter not present */
    }

    /* read second parameter if present */
    if (!SCPI_ParamNumber(context, scpi_special_numbers_def, &param2, FALSE)) {
        /* do something, if parameter not present */
    }

    SCPI_NumberToStr(context, scpi_special_numbers_def, &param1, bf, 15);
    fprintf(stderr, "\tP1=%s\r\n", bf);

    SCPI_NumberToStr(context, scpi_special_numbers_def, &param2, bf, 15);
    fprintf(stderr, "\tP2=%s\r\n", bf);

    SCPI_ResultDouble(context, 0);

    return SCPI_RES_OK;
}

 

This is the output of my first debug session:

 

 

Most likely this library will be a fit for my purpose. At least functional.

I'll have to check if it doesn't use malloc(), UNION or other constructs that aren't allowed by MISRA. The first checks look promising.

 

Here's the full set of commands exercised by the test program:

 

    TEST_SCPI_INPUT("*CLS\r\n");
    TEST_SCPI_INPUT("*RST\r\n");
    TEST_SCPI_INPUT("MEAS:volt:DC? 12,50;*OPC\r\n");
    TEST_SCPI_INPUT("*IDN?\r\n");
    TEST_SCPI_INPUT("SYST:VERS?");
    TEST_SCPI_INPUT("\r\n*ID");
    TEST_SCPI_INPUT("N?");
    TEST_SCPI_INPUT(""); /* emulate command timeout */

    TEST_SCPI_INPUT("*ESE\r\n"); /* cause error -109, missing parameter */
    TEST_SCPI_INPUT("*ESE #H20\r\n");

    TEST_SCPI_INPUT("*SRE #HFF\r\n");

    TEST_SCPI_INPUT("IDN?\r\n"); /* cause error -113, undefined header */

    TEST_SCPI_INPUT("SYST:ERR?\r\n");
    TEST_SCPI_INPUT("SYST:ERR?\r\n");
    TEST_SCPI_INPUT("*STB?\r\n");
    TEST_SCPI_INPUT("*ESR?\r\n");
    TEST_SCPI_INPUT("*STB?\r\n");

    TEST_SCPI_INPUT("meas:volt:dc? 0.01 V, Default\r\n");
    TEST_SCPI_INPUT("meas:volt:dc?\r\n");
    TEST_SCPI_INPUT("meas:volt:dc? def, 0.00001\r\n");
    TEST_SCPI_INPUT("meas:volt:dc? 0.00001\r\n");

    TEST_SCPI_INPUT("test:text 'a'\r\n");
    TEST_SCPI_INPUT("test:text 'a a'\r\n");
    TEST_SCPI_INPUT("test:text 'aa a'\r\n");
    TEST_SCPI_INPUT("test:text 'aaa aaaa'\r\n");
    TEST_SCPI_INPUT("TEST:CHANnellist (@9!2:3!4,5!6)\r\n");

 

And here's the output (errors are expected - the program exercises fault handling too):

 

**Reset
meas:volt:dc
        P1=12
        P2=50
0;MANUFACTURE,INSTR2013,0,01-02
1999.0
MANUFACTURE,INSTR2013,0,01-02
**ERROR: -109, "Missing parameter"
**SRQ: 0x64 (100)
**ERROR: -113, "Undefined header"
-109,"Missing parameter"
**SRQ: 0x60 (96)
**ERROR: 0, "No error"
-113,"Undefined header;IDN?"
96
33
0
meas:volt:dc
        P1=0.01 V
        P2=DEFault
0
meas:volt:dc
        P1=1.112254449840
        P2=1.955364798282
0
meas:volt:dc
        P1=DEFault
        P2=1e-005
0
meas:volt:dc
        P1=1e-005
        P2=1.955364798282
0
TEXT: ***a***
TEXT: ***a a***
TEXT: ***aa a***
TEXT: ***aaa aaaa***
**SRQ: 0x44 (68)
**ERROR: -200, "Execution error"

 

Real World Example

This video shows how you can use the SCPI commands of a Rigol DS1052E oscilloscope.

It's using the proprietary Ultra Sigma software. But it works just from any application that can talk SCPI and is able to connect to the Rigol.

 

 

 

Next Steps

I'll implement a serial interface on my test device with USB. And then I'll develop a single callback that supports *IDN?.

If I have that working, I can try to set up a conversation with LabVIEW.

(note to self: there's a test program in D:\Program Files (x86)\National Instruments\LabVIEW 2014\examples\Instrument IO\Serial\Simple Serial.vi)

 

Related Blog

Create a Programmable Instrument with SCPI - Part 1: Parser Library
Create a Programmable Instrument with SCPI - Part 2: Serial over USB
Create a Programmable Instrument with SCPI - Part 3: First Conversation *IDN?
Create a Programmable Instrument with SCPI - Part 4: Error Handling by Default
Create a Programmable Instrument with SCPI - Part 5: First Hardware Commands
Create a Programmable Instrument with SCPI - Part 6: LabVIEW Integration
Create a Programmable Instrument with SCPI - Part 7: Talk to Hardware Registers

I'm designing a BoosterPack to evaluate GaN devices with the help of a microcontroller.

 

             lmg5200 boosterpack lcd

 

The kit will have a GaN half-bridge that can control an output of 20V and 10A.

Currently the prototype can control switching frequency and duty cycle.

I'm also planning a stretch goal to integrate the design with LabView. You can then use this as a part of a test setup.

 

 

 

The Design Exists

 

I have a working prototype. I modded an existing LMG5200 evaluation kit a while ago.

I removed the discrete PWM generator and replaced it with microcontroller managed signals.

hercules and LMG5200

 

This proof of concept works, both electronics and firmware. I can make a more sturdy version now.

The switching layout is fully based on the design guidelines and the evaluation kit's PCB.

Because of the high switching frequencies and high currents, that part of the design is critical.

I'm trying to place all components similar to the application notes. This will be my first 4-layer PCB design.

 

Status

 

I have the schematic ready.

I had to create a few components and footprints (both for LMG5200 and rotary encoder, footprint only for the inductor).

LMG5200 Hercules BoosterPack schematic

For the PCB, I have a provisional layout. I haven't routed a single trace yet.

But I have uploaded that intermediate status to OSHPark to get an idea of how this device will look like.

Before doing that routing, I first have to verify if I can source all the components that I'm planning to use.

In particular the SMD 360° rotary encoder may be a tricky purchase.

 

board bottom

 

LMG5200 footprint

 

To be continued...

 

Related Blogs
Hercules LaunchPad and GaN FETs - Part 1: Control Big Power with a Flimsy Mouse Scroll Wheel
Hercules LaunchPad and GaN FETs - Part 2: Make a BoosterPack
Hercules LaunchPad and GaN FETs - Part 3a: BoosterPack Layout - Reference Design
Hercules LaunchPad and GaN FETs - Part 3b: BoosterPack Layout - my version
Hercules LaunchPad and GaN FETs - Side Note A: BoosterPack Layout - Custom KiCad Parts
Hercules LaunchPad and GaN FETs - Side Note B: Look at the PCB
Rotary Encoders - Part 1: Electronics
Checking Out GaN Half-Bridge Power Stage: Texas Instruments LMG5200 - Part 1: Preview
Rotary Encoders - Part 4: Capturing Input on a Texas Instruments Hercules LaunchPad with eQEP
Vintage Turntable repair: Can I fix a Perpetuum Ebner from 1958 - part 4 - Hercules LaunchPad Enhanced PWM try-out

I 'm learning embedded Linux with a BeagleBone.  This time I'm using my Windows Desktop as the screen for my board.

 

 

 

Graphic Programs on a headless board.

 

XWindow and Preparation of the Windows PC

 

I'm going to run applications on the BB. These applications want to show a window and graphics.

My BB doesn't have a screen. It will direct the graphics to my Windows laptop.

The activity doesn't require any software installation on the BB. Everything is there.

You have to run an xwindow server on your PC though - a program that will receive the graphics from the BB and draw them on the Windows desktop.

I'm using Cygwin for that. Install the latest version.

There's one change to the default install that you have to do on the 'Select Packages' screen.

Change X11 from Default to Install.

 

Then let the installation rip - this is a good time to do a long household chore because the first download of Cygwin takes a long time.

I have selected to create the Start Menu icons at the end of the install, so that I get an entry in the Start menu for the xwindow server.

After installation, you can start the Cygwin service in several ways. The easiest is to select the XWin Server program from your Start menu.

 

 

 

 

 

You get two new icons in the Tray. The first one - the Cygwin/XServer icon - lets you set preferences on how the xwindow canvas appears on your desktop.

We will not use that in this session. We leave everything as is.

The green icon is a menu that allows you to run a set of linux graphic applications locally on your Windows computer.

We'll use that to start a terminal session. From there we'll contact our BB and kick off graphical apps.

 

To do that, right-click on the X applications menu icon. Then select System Tools -> XTerm.

 

 

The xterm window pops up on your desktop. And that's the last piece of action that's executed on your computer.

You can spot that because the prompt shows my computer's name. It's a local Cygwin linux session.

In the next section, we connect to the BB and start shooting off graphic programs.

 

 

Connect to BeagleBone and Run Graphic Programs

 

Everything is now ready to establish the graphic link between BB and your PC, and run a few graphic applications.

Up until now, we were working on a Cygwin linux session on the PC. After the next step, we're in a linux session on the BB Debian - almost similar as when you go via PuTTY.

In the xterm window, secure shell into your BB. Use the -XY options to allow the BB to tunnel the graphic commands back to your PC xwindow server.

 

ssh -XY debian@192.168.7.2

 

Enter the password of user debian. You see that we have landed in our bb linux session, because the prompt changes to debian@beaglebone.

 

You're now ready to run graphic programs. There are a number of them installed in the /usr/bin/ folder of Debian.

Let's start with the test program xlogo.

That one is typically used to see if everything is set up right.

 

Start it by running this command on the prompt (the & after the command takes care that linux kicks off the program and returns back to the prompt without waiting for the app to finish:

 

 

xlogo &

 

 

If you see a small window popping up on your Windows desktop, you've got success!

 

Now go on and try a few of the other pre-installed applications:

 

xcalc &
xterm &
xclock &
xmessage "Hello, world!" &
xedit &

 

 

This is different than running a Desktop Environment. We're running individual applications here. You don't have a typical KDE, GNOME, Xfce, LXDE, ... experience.

Nothing stops you to install any of these windowing flavours on your BB and run that desktop environment on your Windows screen. It works - but you'll have to do that install.

 

Have fun!

 

 

 

 

BeagleBone - First Little Checks
BeagleBone - Cross Compile c++ on Windows
BeagleBone - Show XWindows Graphic Apps on Windows Desktop