Sunday, May 15, 2016

Borrowed routines for SI5351 and WSPR encoding

Borrowed routines

The interwebz are a wonderful place.  People publish their software for others to use.  I took advantage of this to get a driver for the Si5351 chip, and also to find code to encode my WSPR strings.

SI5351 library

I ported code written by Jason Milldrum & Dana H. Myers.  This code was written for Arduino. Fortunately, the Arduino specifics were isolated to a few functions.  

si5351_read
si5351_write
si5351_write_bulk

One little issue that I ran into was that the I2C bus address in arduino is automatically shifted by the Arduino libraries, but it is not by the HAL libraries for STM.  So, where these routines used "addr", I basically had to use "addr <<1".

I had some initial issues with timing in I2C.  Things would work fine if I had lots of debugging turned on, but would fail if I removed debugging.  Then, I found a sparsely documented HAL_I2C_IsDeviceReady() routine.  By adding this call before all of my I2C reads and writes, the problems cleared up.  At some point, I'll investigate this more thoroughly to make sure that I understand exactly what the issue was.

Below is a before/after sample of one of the changes to get a feel for the changes required:

Vanilla:
uint8_t Si5351::si5351_read(uint8_t addr)
{
uint8_t reg_val;
Wire.beginTransmission(SI5351_BUS_BASE_ADDR);
Wire.write(addr);
Wire.endTransmission();
Wire.requestFrom(SI5351_BUS_BASE_ADDR, 1, false);
while(Wire.available())
{
reg_val = Wire.read();
}
return reg_val;
}
My Version:
uint8_t Si5351::si5351_read(uint8_t addr)
{
uint8_t buffer[] = {addr};
uint8_t value;

    if (HAL_I2C_IsDeviceReady(&Globals.I2cHandle, (uint16_t)SI5351_BUS_BASE_ADDR<<1, 2, 
I2CTIMEOUT) != HAL_OK) {
    Error_Handler();
    }

while(HAL_I2C_Master_Transmit(&Globals.I2cHandle, (uint16_t)SI5351_BUS_BASE_ADDR<<1, (uint8_t*)&buffer, sizeof(buffer), I2CTIMEOUT)!= HAL_OK)
{
/* Error_Handler() function is called when Timeout error occurs.
      When Acknowledge failure occurs (Slave don't acknowledge it's address)
      Master restarts communication */
   if (HAL_I2C_GetError(&Globals.I2cHandle) != HAL_I2C_ERROR_AF)
   {
    Error_Handler();
   }
}

    if (HAL_I2C_IsDeviceReady(&Globals.I2cHandle, (uint16_t)SI5351_BUS_BASE_ADDR<<1, 2, I2CTIMEOUT) != HAL_OK) {
    Error_Handler();
    }

while(HAL_I2C_Master_Receive(&Globals.I2cHandle, (uint16_t)SI5351_BUS_BASE_ADDR<<1, (uint8_t *)&value, 1, I2CTIMEOUT) != HAL_OK)
{
/* Error_Handler() function is called when Timeout error occurs.
          When Acknowledge failure occurs (Slave don't acknowledge it's address)
          Master restarts communication */
if (HAL_I2C_GetError(&Globals.I2cHandle) != HAL_I2C_ERROR_AF)
{
Error_Handler();
}
  }

  return value;
}

WSPR Encoding routine

I poked around and found a few different options for WSPR encoding.  I found some truly wretched code in a few Arduino samples I found.  I'm always nervous about code with malloc() and free() calls.  One particularly good looking implementation, however, includes support for JT65, JT9, JT4 and WSPR can be found at this link right here.

Ultimately, though, being the contrarian that I am, I found an even leaner and meaner encoding routine written by Mark VandeWettering called "genwspr".

The code is VERY small and lean, with no malloc() or free() calls, which made me happy.  I can't say that I understand it one tiny bit, but it creates a tone array of values to use for making the WSPR signal.  It was trivial to just pick up his code and port it into my project. 

I was able to take the output of his routine and compare it to output from the "wsprcode.exe" program documented in the WSPR_2.0 User manual, and found it matched exactly.  Good 'nuff for me!




4 comments:

  1. Could you share the code? I can not find a working library for the STM32.

    ReplyDelete
    Replies
    1. I mean code for SI5351. This will be very useful for me.

      Delete
    2. Thomas, I'd be happy to share it. Are you using the STM32CubeMX HAL libraries? That's what I coded it to.

      Mike

      Delete
  2. Hello,

    I come across ur blog with search. I tried using HAL_I2C_IsDeviceReady() to verify if my slave device is ready for communication. It is giving HAL_OK or 0.

    Please look at this post, it is my question on StackExchange:
    http://electronics.stackexchange.com/questions/282390/stm32f411rct6-not-talking-to-lcd-panel-i2c-and-hal-library

    I tried sending ten bytes at once using HAL_I2C_Master_Trasmit() as in init_LCD(), I am getting HAL_ERROR or 1 value.

    When I try sending just first two bytes of init_LCD() instead of 10 bytes, it is returning HAL_OK or 0, but it does not configure my LCD.

    Please update me if possible.

    Thanks,

    ReplyDelete