• AVR Freaks

AnsweredHot!PIC16F1823 Random/White noise signal

Author
btommo
Junior Member
  • Total Posts : 112
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
2019/11/07 04:08:56 (permalink)
0

PIC16F1823 Random/White noise signal

Hi All,
 
I've trying to generate white noise for an audio application, I've been given some assembler code but wish to translate it to xc8 C, attached is the code, my interpretation and the original question as microchip seems to block it.
 
 
In the circuit I am using it on has C0, C1, C2 each connected to IN- of an LM393 through a resistor (tones added together)
The issue I am having is that a constant tone of the same frequency is generated rather that white/random noise, apparently timing is critical with white noise generation.
 
I'm using the PWM to control a SMPS in the circuit.
 
Any help or advice is appreciated, if anyone has any experience with generating a white noise tone.
 
#1
ric
Super Member
  • Total Posts : 24202
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: PIC16F1823 Random/White noise signal 2019/11/07 04:20:41 (permalink)
+1 (1)
Your shift left is faulty, it is NOT emulating the assembly RLF instruction.
You are NOT carrying the carry value from each byte to the next higher byte.
It also seems strange that you declare RotateLeftCarry() to return an "int" value, when you are only going to store it into an unsigned char.
It would be much simpler in C to just declare a 32 bit unsigned integer and ask the compiler to shift it for you.

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#2
btommo
Junior Member
  • Total Posts : 112
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: PIC16F1823 Random/White noise signal 2019/11/07 04:38:07 (permalink)
0
I did wondering if my interpretation of RLF instruction was correct or not, so the MSB of RND0 becomes the LSB of RND1 and so on rather than it circulating RND0 (RND0 MSB becomes RND0 LSB) if the RLF instructions would in that was it would be simpler to shift the 32bit int making it's MSB it's LSB then making LATC = (RND & 0x0F) to show the lowest byte.
 
But then there's the fact that the highest byte needs to be stored in TEMP with it's nibbles swaps, but then it isn't entirely clear on the input TEMP has on the output.
post edited by btommo - 2019/11/07 04:43:00
#3
btommo
Junior Member
  • Total Posts : 112
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: PIC16F1823 Random/White noise signal 2019/11/08 08:19:18 (permalink)
0
I tried with a 32 bit variable, please see below;
 

/**
Generated Main Source File
Company:
Microchip Technology Inc.
File Name:
main.c
Summary:
This is the main file generated using PIC10 / PIC12 / PIC16 / PIC18 MCUs
Description:
This header file provides implementations for driver APIs for all modules selected in the GUI.
Generation Information :
Product Revision : PIC10 / PIC12 / PIC16 / PIC18 MCUs - 1.77
Device : PIC16F1823
Driver Version : 2.00
*/

#include "mcc_generated_files/mcc.h"
uint8_t RND0 = 0xAF;
uint8_t RND1 = 0x50;
uint8_t RND2 = 0x05;
uint8_t RND3 = 0x34;
uint8_t TEMP;
uint8_t TEMP2;
uint32_t RND = 0x340550AF;
uint8_t swapNibbles(uint8_t x)
{
return ( ((x & 0x0F) << 4) | ((x & 0xF0) >> 4) );
}
uint32_t swapNibbles2(uint32_t x)
{
return ( (((x & 0x0F000000) << 4) | ((x & 0xF0000000) >> 4) ) + (x & 0x00FFFFFF)) ;
}
uint8_t RotateLeftCarry(uint8_t x)
{
return((x << 1) + (x >> 7 & 0x01));
}
/*
Main application
*/
void main(void)
{
// initialize the device
SYSTEM_Initialize();
// When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
// Use the following macros to:
// Enable the Global Interrupts
//INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptEnable();
// Disable the Global Interrupts
//INTERRUPT_GlobalInterruptDisable();
// Disable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptDisable();
while (1)
{
/*TEMP = swapNibbles(RND3); // swap high and low nibble 51uS
TEMP2 = RotateLeftCarry(RND3); //shift left and carry MSB-> LSB 56uS
TEMP ^= TEMP2; //exclusive OR TEMP and TEMP2 and store in TEMP 4uS
TEMP = RotateLeftCarry(TEMP); //shift left and carry MSB-> LSB 55uS

RND0 = RotateLeftCarry(RND0);//shift left and carry MSB-> LSB 55uS
RND1 = RotateLeftCarry(RND1);//shift left and carry MSB-> LSB 55 uS
RND2 = RotateLeftCarry(RND2);//shift left and carry MSB-> LSB 55uS
RND3 = RotateLeftCarry(RND3);//shift left and carry MSB-> LSB 55uS
LATC = RND0; //show RND0 on LATC 5uS*/
RND = (RND << 1) + (RND >> 31 & 0x01);
LATC = RND & 0x0F;

// Add your application code
}
}
/**
End of File
*/

 
Outcome was a constant tone rather than random/white noise, I didn't think white noise would be this difficult to generate.
#4
NorthGuy
Super Member
  • Total Posts : 5733
  • Reward points : 0
  • Joined: 2014/02/23 14:23:23
  • Location: Northern Canada
  • Status: offline
Re: PIC16F1823 Random/White noise signal 2019/11/08 08:42:39 (permalink)
+1 (1)
Any random number generator will have a cycle, but the cycle of random number generator based on shifts will be very short. Standard way is to use multiplication:
 
https://en.wikipedia.org/wiki/Linear_congruential_generator
 
 
#5
Ian.M
Super Member
  • Total Posts : 13263
  • Reward points : 0
  • Joined: 2009/07/23 07:02:40
  • Location: UK
  • Status: offline
Re: PIC16F1823 Random/White noise signal 2019/11/08 10:01:42 (permalink) ☼ Best Answerby btommo 2019/11/11 04:46:40
+3 (3)
However if you need *fast*random numbers on an 8 bit MCU without a hardware multiplier, that's not a good approach.  You'd do better to look at Galois LFSRs (see https://en.wikipedia.org/wiki/Linear-feedback_shift_register ), with the constraint that if you are working in C,  the maximum shift register length that can be efficiently handled without looping is the length of the platform's largest unsigned integer type (i.e. 32 bits for XC8). 
 
Why Galois rather than Fibonacci?  Because you don't have to have convoluted code to gather all the feedback taps into a single bit, as for a Galois LFSR, you only need to conditionally XOR in the feedback mask if the bit shifted out was 1.
 
See https://www.maximintegrated.com/en/design/technical-documents/app-notes/4/4400.html for some hints on a workable C implementation for a Galois LFSR on a MCU, and what taps to use.

--
NEW USERS: Posting images, links and code - workaround for restrictions.
I also support http://picforum.ric323.com because this forum is sometimes too broken to use!
#6
davea
Senior Member
  • Total Posts : 157
  • Reward points : 0
  • Joined: 2016/01/28 13:12:13
  • Location: 0
  • Status: offline
Re: PIC16F1823 Random/White noise signal 2019/11/08 17:02:23 (permalink)
0
I've trying to generate white noise for an audio application
 
you should consider pink noise it has a 1/Freq power density (will not overheat tweeters) 
https://en.wikipedia.org/wiki/Pink_noise 
#7
Ian.M
Super Member
  • Total Posts : 13263
  • Reward points : 0
  • Joined: 2009/07/23 07:02:40
  • Location: UK
  • Status: offline
Re: PIC16F1823 Random/White noise signal 2019/11/08 21:33:12 (permalink)
+1 (1)
However pink noise is a PITA to generate digitally on a low end MCU.  If you need it, its probably better to approximate a 3dB/octave rolloff filter in the analog domain.   A simple RC filter is unfortunately 6dB/octave so the implementation details are non-trivial, but it can be done with reasonable accuracy for the audible spectrum with only nine passives.  See PDF page 69 of http://www.bitsavers.org/components/national/_dataBooks/1976_National_Audio_Handbook.pdf and I would suggest following it with a unit gain OPAMP buffer.

--
NEW USERS: Posting images, links and code - workaround for restrictions.
I also support http://picforum.ric323.com because this forum is sometimes too broken to use!
#8
btommo
Junior Member
  • Total Posts : 112
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: PIC16F1823 Random/White noise signal 2019/11/11 04:46:32 (permalink)
0
Thanks Ian, I followed the Maxim link for the Galois LFSR and it provided the sound I required
#9
Ian.M
Super Member
  • Total Posts : 13263
  • Reward points : 0
  • Joined: 2009/07/23 07:02:40
  • Location: UK
  • Status: offline
Re: PIC16F1823 Random/White noise signal 2019/11/11 05:37:06 (permalink)
+1 (1)
Post your working code, for the benefit of the next newb who needs a fast LFSR random sequence genetator.  Also, we may be able to otimise it for XC8 and tune it for a higher sample rate

--
NEW USERS: Posting images, links and code - workaround for restrictions.
I also support http://picforum.ric323.com because this forum is sometimes too broken to use!
#10
btommo
Junior Member
  • Total Posts : 112
  • Reward points : 0
  • Joined: 2017/07/07 02:59:33
  • Location: 0
  • Status: offline
Re: PIC16F1823 Random/White noise signal 2019/11/11 06:02:15 (permalink)
+2 (2)

/**
Generated Main Source File
Company:
Microchip Technology Inc.
File Name:
main.c
Summary:
This is the main file generated using PIC10 / PIC12 / PIC16 / PIC18 MCUs
Description:
This header file provides implementations for driver APIs for all modules selected in the GUI.
Generation Information :
Product Revision : PIC10 / PIC12 / PIC16 / PIC18 MCUs - 1.77
Device : PIC16F1823
Driver Version : 2.00
*/

#include "mcc_generated_files/mcc.h"
#define POLY_MASK_32 0xB4BCD35C
#define POLY_MASK_31 0x7A5BC2E3
uint32_t lfsr32, lfsr31;
int shift_lfsr(uint32_t *lfsr, uint32_t polynomial_mask)
{
int feedback;

feedback = *lfsr & 1;
*lfsr >>= 1;
if(feedback == 1)
*lfsr ^= polynomial_mask;
return *lfsr;
}
void init_lfsrs(void)
{
lfsr32 = 0xABCDE;
lfsr31 = 0x23456789;
}
uint8_t get_random(void)
{
shift_lfsr(&lfsr32, POLY_MASK_32);
return(shift_lfsr(&lfsr32, POLY_MASK_32) ^ shift_lfsr(&lfsr31, POLY_MASK_31)) & 0xFFFF;
}
/*
Main application
*/
void main(void)
{
// initialize the device
SYSTEM_Initialize();
uint16_t random_value;
init_lfsrs();
// When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
// Use the following macros to:
// Enable the Global Interrupts
INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
INTERRUPT_PeripheralInterruptEnable();
// Disable the Global Interrupts
//INTERRUPT_GlobalInterruptDisable();
// Disable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptDisable();
while (1)
{

random_value = get_random();
LATC = random_value;
// Add your application code
}
}
/**
End of File
*/
 

#11
ric
Super Member
  • Total Posts : 24202
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: PIC16F1823 Random/White noise signal 2019/11/11 12:23:23 (permalink)
0
It looks a bit odd that shift_lfsr() is returning a uint32_t value, but its return type is "int" which is a signed 16 bit type.
I realise that only the bottom 16 bits of the value are actually used by the calling code, but it would be much more transparent if the return type was "uint16_t", and the final instruction was actually:
  return *lfsr & 0xFFFF;


I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#12
Ian.M
Super Member
  • Total Posts : 13263
  • Reward points : 0
  • Joined: 2009/07/23 07:02:40
  • Location: UK
  • Status: offline
Re: PIC16F1823 Random/White noise signal 2019/11/12 01:02:34 (permalink)
0
Tidied up and somewhat optimised (for speed, not size) single file version that doesn't need any MCC generated files

/**
File Name:
main.c
Summary:
Dual Galois LFSR random number generator demo.
see: https://www.maximintegrated.com/en/design/technical-documents/app-notes/4/4400.html
Optimised for 8 bit embedded platforms by Ian.M
Device : PIC16F1823
*/
#include <xc.h>
#include <stdint.h>
// Define FAST to use optimised non-pointer shift_lfsr functions, recommended
// for baseline and standard midrange PICs (without FSR offset capability).
// May also be desirable on other PICS to avoid passing pointers and masks
#define FAST

#define POLY_MASK_32 0xB4BCD35C
#define POLY_MASK_31 0x7A5BC2E3
uint32_t lfsr32=0xABCDE, lfsr31=0x23456789; //Seed values must be non-zero
#ifndef FAST
// Generic form of shift_lfsr() uses pointers
// which may not optimise well on low end devices

void shift_lfsr(uint32_t *lfsr, uint32_t polynomial_mask){
if(*lfsr & 1){
*lfsr >>= 1;
*lfsr ^= polynomial_mask;
}else{
*lfsr >>= 1;
}
}
#else
// Fast non-pointer versions
void shift_lfsr32(void){
if(lfsr32 & 1){
lfsr32 >>= 1;
lfsr32 ^= POLY_MASK_32;
}else{
lfsr32 >>= 1;
}
}
void shift_lfsr31(void){
if(lfsr31 & 1){
lfsr31 >>= 1;
lfsr31 ^= POLY_MASK_31;
}else{
lfsr31 >>= 1;
}
}
#endif
uint16_t get_random(void){
#ifndef FAST
// Generic pointer version
shift_lfsr(&lfsr32, POLY_MASK_32);
shift_lfsr(&lfsr32, POLY_MASK_32);
shift_lfsr(&lfsr31, POLY_MASK_31);
#else
// Non-pointer version
shift_lfsr32();
shift_lfsr32();
shift_lfsr31();
#endif
return(lfsr32^lfsr31) & 0xFFFF;
}
//*** Main application ***
void main(void){
uint16_t random_value;

TRISC=0; // Port C all outputs
ANSELC=0; // and all digital

while (1){
random_value = get_random();
LATC = random_value;
}
}
//*** End of File ***

 
N.B. generating a full random number like this is total overkill unless the O.P. has a full  8 bit parallel or R-2R DAC connected to the output port.  Simply call shift_lfsr() three times on the 32 bit lfsr, then copy the three LSBs of that lfsr to the port.   Assuming a 100KHz sample rate, the repetition period will be fractionally under four hours, an even a ten minute period would be sufficient to avoid most humans noticing its repetitive.
 
Also, to improve 'whiteness', it badly needs a sandwich delay in the main loop to set the sample rate so it isn't determined by the execution path through the shift_lfsr function(s).
 

--
NEW USERS: Posting images, links and code - workaround for restrictions.
I also support http://picforum.ric323.com because this forum is sometimes too broken to use!
#13
Jump to:
© 2019 APG vNext Commercial Version 4.5