Debugging with Rigol DHO804

Thread Starter

cbarb2747

Joined Apr 15, 2025
2
I am trying to develop my skills at embedded systems and am trying to learn how to use my oscilloscope to debug. I am using a texas instruments board and am trying to debug certain pins to debug SPI communication issues between boards. I just wrote a simple program on an arduino to print out HI through the spi protocol to try and figure out how to use the scope. I debugged the pins with a logic analyzer and saw that the pins indeed are outputting a clock signal and the data HI. When I try to decode the data on the scope, the frequencies look correct, but I do not see any decoded data. Here are my settings and a picture of the signals. Thanks in advance.

IMG_6442.jpg



IMG_6441.jpg
 

nsaspook

Joined Aug 27, 2009
16,250
Make sure all of your probes are set correctly. If you have 5V SPI, then all of the channel should be set to 5V, with the probe switch set to 10X on the probe AND 10X on the scope channel configuration. Use the calibration signal to check your channel settings.
Increase your Mem Depth, mine is set to 5M.
1744773583728.png
1744773609073.png
I'm using CS CHAN 3 for the decode trigger CLK CHAN1, MOSI CHAN 2 for the display SPI signal on the scope. Trigger set to Normal and single so we have a solid data capture to decode.
1744773724453.png
1744773943393.png
15 MHz SPI to the GLCD display.
1744773665962.png
1744773829372.png
1744773558729.png
 

nsaspook

Joined Aug 27, 2009
16,250
Another set of SPI decode examples with decode CS trigger set on timeout. The timeout is set to be greater than the spacing between SPI byte transmissions.
1744812391925.png
1744812435090.png
SPI Mode 3
1744812517476.png

Zoom back to the entire display memory update sequence.
1744812573744.png

This update sequence uses DMA for speed and to save main thread processor resources.
C:
void OledUpdate(void)
{
#ifdef DMA_STATE_M
    wait_lcd_done();
    SPI1DmaChannelHandler_State(0, DMA_MAGIC); // set DMA state machine init mode to start transfers
    return;
#else
#endif
}

/*
* start a GLCD update: Called in user code with contextHandle set to DMA_MAGIC for a background screen update,
* during background transfers this function is used as the callback for DMA transfer complete events to
* sequence commands and data to the GLCD via the SPI port using the dstate ENUM variable
* dstate is set to 'D_idle' when the complete set of transfers is done.
*/
void SPI1DmaChannelHandler_State(DMAC_TRANSFER_EVENT event, uintptr_t contextHandle)
{
    static int32_t ipag = 0; // buffer page number
    static uint8_t* pb; // buffer page address

    // back to mainline code, GLCD updates in background using DMA and interrupts
    LCD_UNSELECT();
    if (contextHandle == DMA_MAGIC) { // re-init state machine for next GLCD update
        dstate = D_init;
    }

    switch (dstate) {
    case D_init:
        ipag = 0;
        if (disp_frame) { // select flipper buffer
            pb = rgbOledBmp0;
        } else {
            pb = rgbOledBmp1;
        }
        /* FALLTHRU */
    case D_page: // send the page address commands via DMA
        LCD_SELECT(); // enable the GLCD chip for SPI transfers
        dstate = D_buffer;
        lcd_moveto_xy(ipag, 0); // calculate address data nibbles and store in rgbOledBmp_page array
        /*
         * DMAC_ChannelCallbackRegister and SPI setup in OledInit
         */
        LCD_CMD();
        DMAC_ChannelTransfer(DMAC_CHANNEL_0, (const void *) rgbOledBmp_page, (size_t) 4, (const void*) &SPI1BUF, (size_t) 1, (size_t) 1);
        break;
    case D_buffer: // send the GLCD buffer data via DMA
        ipag++;
        if (ipag <= cpagOledMax) {
            LCD_SELECT(); // enable the GLCD chip for SPI transfers
            dstate = D_page;
            LCD_DRAM();
            DMAC_ChannelTransfer(DMAC_CHANNEL_0, (const void *) pb, (size_t) ccolOledMax, (const void*) &SPI1BUF, (size_t) 1, (size_t) 1);
            pb += ccolOledMax;
        } else {
            dstate = D_idle;
            LCD_UNSELECT(); // all done with the GLCD
        }
        break;
    case D_idle:
    default:
        LCD_UNSELECT();
        break;
    }
}
The first four bytes are the D_Page code in the switch statement for setting the display.
1744813380528.png
The hunks in the total transfer are byte send in the D_buffer part of the switch statement per page of display memory using ipag as the page number to transfer.
When the last page of display memory is sent, the dstate = is set to D_idle and the LCD CS is deselected. Each DMA page transfer sends a DMA compete interrupt that calls SPI1DmaChannelHandler_State until all pages are complete.

You can use the scope to verify all of this works as designed or not if there are bugs in the implementation of the display driver code or hardware.

1744813041062.png
 
Top