Outputting a bitstream onto a pin in verilog - output

I need to output a 32bit bit-stream onto a pin in verilog. I know verilog has the streaming operators pack and unpack but I do not believe they will do what I want it to do.
I have 32x512 FIFO RAM in which data is stored. Data for the variable "I" stored on the first 32 bits and the data for variable "Q" is stored on the next 32 bits (the rest of FIFO saves data in this alternating fashion). I need to continually get a 32bit stream off the FIFO RAM and output the 32bit data stream onto a pin. My FIFO has three output signals(a signal for the 32 bit data stream(32_data), a signal to say when the FIFO is empty (32_empty), and a signal to say when the FIFO is full(32_full)) My sudo code is the following (It's sudo code because I know how to do everything else but the part I need help with and I wanted to keep it simple for understanding):
process # posedge clock
begin
if (32_empty != 1) then //if the FIFO has data
if (32_full == 1) then //if the FIFO is full, then we lose data (for testing purposes to know if I need to make the RAM bigger
PIN_1 <= 1; //output onto a pin that the FIFO is full
PIN_2 <= 0; //clear pin 2 from outputting data for "I"
PIN_3 <= 0; //clear pin 3 from outputting data for "Q"
else if (en_Q == 0)
(stream 32bit data for variable "I" onto pin 2) //variable "I" output//HELP-This is where I need help figuring out how to stream the output, 32_data, onto a pin
en_Q <= ~en_Q; // toggle en_Q so next 32bit stream will be for "Q"
else if (en_Q ==1)
(stream 32bit data for variable "Q" onto pin 3) //variable "Q" output//HELP-This is where I need help figuring out how to stream the output, 32_data, onto a pin
en_Q <= ~en_Q; // toggle en_Q so next 32bit stream will be for "I"
end
If you could help me with figuring out how to stream a 32 bit data stream onto a pin, that would be great!
Thanks in advance
I have added the suggestion. Could I put the data on the pins with a for loop? The following is my code segment and the bottom part is the shift register and outputting to a pin:
`// Wires and registers related to data capturing
wire capture_clk;
reg [31:0] capture_data;
wire capture_en;
reg [4:0] slowdown;
wire capture_full;
reg capture_open;
reg capture_open_cross;
reg capture_has_been_full;
reg capture_has_been_nonfull;
reg has_been_full_cross;
reg has_been_full;
// Data capture section
// ====================
always #(posedge capture_clk)
begin
if (capture_en)
capture_data <= user_w_write_32_data; // Bogus data source
// The slowdown register limits the data pace to 1/32 the bus_clk
// when capture_clk = bus_clk. This is necessary, because the
// core in the evaluation kit is configured for simplicity, and
// not for performance. Sustained data rates of 200 MB/sec are
// easily reached with performance-oriented setting.
// The slowdown register has no function in a real-life application.
slowdown <= slowdown + 1;
// capture_has_been_full remembers that the FIFO has been full
// until the file is closed. capture_has_been_nonfull prevents
// capture_has_been_full to respond to the initial full condition
// every FIFO displays on reset.
if (!capture_full)
capture_has_been_nonfull <= 1;
else if (!capture_open)
capture_has_been_nonfull <= 0;
if (capture_full && capture_has_been_nonfull)
capture_has_been_full <= 1;
else if (!capture_open)
capture_has_been_full <= 0;
end
// The dependency on slowdown is only for bogus data
assign capture_en = capture_open && !capture_full &&
!capture_has_been_full &&
(slowdown == 0);
// Clock crossing logic: bus_clk -> capture_clk
always #(posedge capture_clk)
begin
capture_open_cross <= user_r_read_32_open;
capture_open <= capture_open_cross;
end
// Clock crossing logic: capture_clk -> bus_clk
always #(posedge bus_clk)
begin
has_been_full_cross <= capture_has_been_full;
has_been_full <= has_been_full_cross;
end
// The user_r_read_32_eof signal is required to go from '0' to '1' only on
// a clock cycle following an asserted read enable, according to Xillybus'
// core API. This is assured, since it's a logical AND between
// user_r_read_32_empty and has_been_full. has_been_full goes high when the
// FIFO is full, so it's guaranteed that user_r_read_32_empty is low when
// that happens. On the other hand, user_r_read_32_empty is a FIFO's empty
// signal, which naturally meets the requirement.
assign user_r_read_32_eof = user_r_read_32_empty && has_been_full;
assign user_w_write_32_full = 0;
// The data capture clock here is bus_clk for simplicity, but clock domain
// crossing is done properly, so capture_clk can be an independent clock
// without any other changes.
assign capture_clk = bus_clk;
async_fifo_32x512 fifo_32 //FIFO created using Xilinx FIFO Generator Wizard
(
.rst(!user_r_read_32_open),
.wr_clk(capture_clk),
.rd_clk(bus_clk),
.din(capture_data),
.wr_en(capture_en),
.rd_en(user_r_read_32_rden),
.dout(user_r_read_32_data),
.full(capture_full),
.empty(user_r_read_32_empty)
);
reg Q_en = 1'b0; //starting value is 0 because first 32bit is I
reg [31:0] data_outI;
reg [31:0] data_outQ;
reg I;
reg Q;
integer counter;
always #(posedge bus_clk) begin
if(Q_en == 1'b0) begin //To output to I signal
data_outI <= user_r_read_32_data;
for (counter = 0; counter < 32; counter = counter + 1) begin //output to pins
I = data_outI[0];
data_outI <= (data_outI >> 1);
Q = data_outQ[0];
data_outQ <= (data_outQ >> 1);
end
Q_en <= ~Q_en;
end
else if(Q_en == 1'b1) begin //To output to Q signal
data_outQ <= user_r_read_32_data;
for (counter = 0; counter < 32; counter = counter + 1) begin //output to pins
I = data_outI[0];
data_outI <= (data_outI >> 1);
Q = data_outQ[0];
data_outQ <= (data_outQ >> 1);
end
Q_en <= ~Q_en;
end
end
assign PS_GPIO_ONE_I = I; //Assign Pin I
assign PS_GPIO_TWO_Q = Q; //Assign Pin Q
`

Basically, you'd want to do something like the following:
Fetch an item from the fifo into a 32 bit register (lets call data)
Each clock cycle, put the lsb of data onto the pin, and then right shift data by one value.
Keep repeating this shifting for 32 clock cycles, until all of the data has been shifted out.
Toggle the value of en_Q, and fetch another 32 bit item.
You should be able to make a small state machine that can handle this sequence. You can't shift out all 32 bits in a single clock cycle as you have done in your pseudo-code, unless you also have a 32x clock available, and that would likely be a more complicated design.

Related

past date straight line linear regression indicator with added rate of return (price/time) of the regression

I am trying to make an indicator out of the --straight line-- linear regression pinescript drawing tool included in tradingview (not their regression channel tool or any type least squares moving average/moving regression which plots a continuous curved line). I wish to see one straight line through the chart prices defined in the custom time period input. The plot of this straight line will have acustom start time and length to define the end (or even better an end time instead f length). Next, I wish to add a rate of return feature by taking the total price move of the straight regression line from beginning to end, divided by # of time periods between the start and end date. I have tried the code seen here but I am getting a curved line, not straight. Then for the next step, I am not sure how to get the start and end price point of the regression line to divide by the total time period.
//#version=4
study("lreg ", shorttitle="run-ave", overlay=true)
timeYear = input(2022, title="Year", minval=1991, maxval=2100, type=input.integer)
timeMonth = input(1, title="Month", minval=1, maxval=12, type=input.integer)
timeDay = input(04, title="Day", minval=1, maxval=31, type=input.integer)
timeHours = input(9, title="Hours", minval=0, maxval=23, type=input.integer)
timeMinutes = input(30, title="Minutes", minval=0, maxval=59, type=input.integer)
timeSeconds = input(0, title="Seconds", minval=0, maxval=59, type=input.integer)
length = input(14)
// Initilization of variables only once
var delta = 0
// start time at 0 from a particular time interval
if(year == timeYear and month == timeMonth and dayofmonth == timeDay and hour == timeHours and minute == timeMinutes and second == timeSeconds)
delta := 0
// Count number of bars
if(year >= timeYear and month >= timeMonth and dayofmonth > timeDay)
delta += 1
plotchar(delta, title="days passed from startdate", color=color.green, char='')
// rate of change and moving average of ROC
source = input(close, "Source")
float lreg = na
float lregg = 0
if delta >= 1
lreg:= linreg(close, length, offset=0)
plot(lreg)

Task watchdog got triggered./abort() was called at PC 0x400de07b on core 0

I am on an Autonomous GPS robot project. When I am running the below code after some time the esp32(devkit v1) reboots and this goes on repeating.
Pause for Startup... 3
Pause for Startup... 2
Pause for Startup... 1
Searching for Satellites
Searching for Satellites
GPS Waypoint 1 Set Waypoint #1: 0.000000 , 0.000000
Waypoint #2: 0.000000 , 0.000000
5 Satellites Acquired10.190620
76.424872
25.190620
47.424872
YOYYYYO
Go to Waypoint
E (98333) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (98333) task_wdt: - async_tcp (CPU 0/1)
E (98333) task_wdt: Tasks currently running:
E (98333) task_wdt: CPU 0: IDLE0
E (98333) task_wdt: CPU 1: async_tcp
E (98333) task_wdt: Aborting.
abort() was called at PC 0x400de07b on core 0
Backtrace: 0x4008cbf8:0x3ffbe170 0x4008ce29:0x3ffbe190 0x400de07b:0x3ffbe1b0 0x40084f01:0x3ffbe1d0 0x40148e07:0x3ffbc0d0 0x400df42b:0x3ffbc0f0 0x4008ab01:0x3ffbc110 0x4008930d:0x3ffbc130
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:8896
load:0x40080400,len:5816
entry 0x400806ac
Welcome
Autonmous Mode Initiated...
IP Address: 192.168.1.18
Compass setting done
iam here1
Pause for Startup...
Pause for Startup... 10
Pause for Startup... 9
Pause for Startup... 8
YOYYYYO
Go to Waypoint
Pause for Startup... 7
Pause for Startup... 6
Pause for Startup... 5
Pause for Startup... 4
Pause for Startup... 3
E (10128) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (10128) task_wdt: - async_tcp (CPU 0)
E (10128) task_wdt: Tasks currently running:
E (10128) task_wdt: CPU 0: Tmr Svc
E (10128) task_wdt: CPU 1: IDLE1
E (10128) task_wdt: Aborting.
abort() was called at PC 0x400de07b on core 0
Backtrace: 0x4008cbf8:0x3ffbe170 0x4008ce29:0x3ffbe190 0x400de07b:0x3ffbe1b0 0x40084f01:0x3ffbe1d0 0x4000bfed:0x3ffbd060 0x4008a489:0x3ffbd070 0x400827d1:0x3ffbd090 0x40082843:0x3ffbd0b0 0x4008b825:0x3ffbd0d0 0x4008b924:0x3ffbd100 0x4008930d:0x3ffbd130
Rebooting...
ets Jun 8 2016 00:22:57
This is the msg that appears on the serial monitor. I tried debugging but can't find why this is happening.
The Code is really big, so I have uploaded only a part of it.
// CompaSerial Variables & Setup
HMC5883L compass;
int16_t mx, my, mz; // variables to store x,y,z axis from compass (HMC5883L)
int desired_heading; // initialize variable - stores value for the new desired heading
int compass_heading; // initialize variable - stores value calculated from compass readings
int compass_dev = 5; // the amount of deviation that is allowed in the compass heading - Adjust as Needed
// setting this variable too low will cause the robot to continuously pivot left and right
// setting this variable too high will cause the robot to veer off course
int Heading_A; // variable to store compass heading
int Heading_B; // variable to store compass heading in Opposite direction
int pass = 0; // variable to store which paSerial the robot is on
//*****************************************************************************************************
// GPS Locations
unsigned long Distance_To_Home; // variable for storing the distance to destination
int ac =0; // GPS array counter
int wpCount = 0; // GPS waypoint counter
double Home_LATarray[2]; // variable for storing the destination Latitude - Only Programmed for 5 waypoint
double Home_LONarray[2]; // variable for storing the destination Longitude - up to 50 waypoints
int increment = 0;
//*****************************************************************************************************
// HTML Page
AsyncWebServer server(80);
const char* ssid = "******";
const char* password = "******";
const char* PARAM_INPUT_1 = "input1";
const char* PARAM_INPUT_2 = "input2";
const char* PARAM_INPUT_3 = "input3";
const char* PARAM_INPUT_4 = "input4";
const char* PARAM_COMMIT = "commit";
double lati1;
double logi1;
double lati2;
double logi2;
// HTML web page to handle 4 input fields
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
<h2>Autonomus GPS Robot Car<h2>
<h3> Submit your Destination coordinates</h3>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<style>
a {
border: 10px solid powderblue;
padding: 10px;
color: red;
font-family: verdana;
font-size: 150%;
}
</style>
</head>
<body>
<form action="/get" >
<br>
Waypoint 1 Latitude : <input type="text" name="input1">
<br>
<br>
Waypoint 1 Longitude: <input type="text" name="input2">
<br><br>
<br>
Waypoint 2 Latitude : <input type="text" name="input3">
<br>
<br>
Waypoint 2 Longitude: <input type="text" name="input4">
<br><br>
<input type="submit" value="Submit">
<br>
<br><br>
<br><br>
<a href="/go" >Go to Destination</a>
<br><br> <br><br>
<br><br>
<a href="/clear" > Clear waypoints</a>
</form>
</body>
</html>)rawliteral";
void notFound(AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not found");
}
//*****************************************************************************************************
// Extras
#define autopilot 18
void gesturecontroll();
void getGPS();
void getCompass();
void Forward();
void Forward_Meter();
void Reverse();
void LeftTurn();
void RightTurn();
void SlowLeftTurn();
void SlowRightTurn();
void StopCar();
void setWaypoint();
void move();
void Startup();
void goWaypoint();
void clearWaypoints();
int blueToothVal;
int flag=0;
int button;
void setup()
{ Serial.begin(115200); // Serial 0 is for communication with the computer
Serial.println("Welcome");
pinMode(autopilot, INPUT);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
button = digitalRead(autopilot);
if (button == HIGH)
{ flag=15;
Serial.println("Manual Control initated");
Serial.println("ESPNow/Basic/Slave Example");
//Set device in AP mode to begin with
WiFi.mode(WIFI_AP);
// configure device AP mode
// This is the mac address of the Slave in AP Mode
esp_wifi_set_mac(ESP_IF_WIFI_STA, &mac[0]);
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
// Init ESPNow with a fallback logic
if (esp_now_init()!=0)
{
Serial.println("*** ESP_Now init failed");
while(true) {};
}
// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info.
esp_now_register_recv_cb(OnDataRecv);
Serial.print("Aheloiioi"); // the remaining code for above part is not uploaded since when switch is pulled this part of code works perfectly
}
else{
S2.begin(9600, SERIAL_8N1, RXPin, TXPin); // Serial 2 is for GPS communication at 9600 baud - DO NOT MODIFY - Ublox Neo 6m
flag=0;
// pinMode(LED_BUILTIN, OUTPUT); // An LED indicator - Not Used
Serial.println("Autonmous Mode Initiated...");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed!");
return;
}
Serial.println();
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
CompaSerial////////////////////////////////////////////////////////////////////////////////////
Wire.begin(); // Join I2C bus used for the HMC5883L compass
//compass.init();
compass.begin(); // initialize the compass (HMC5883L)
compass.setRange(HMC5883L_RANGE_1_3GA); // Set measurement range
compass.setMeasurementMode(HMC5883L_CONTINOUS); // Set measurement mode
compass.setDataRate(HMC5883L_DATARATE_30HZ); // Set data rate
compass.setSamples(HMC5883L_SAMPLES_8); // Set number of samples averaged
compass.setOffset(0,0);
Serial.println("Compass setting done");
Startup(); // Run the Startup procedure on power-up one time
}
}
// Main Loop
void loop()
{ button = digitalRead(autopilot);
if (button == HIGH && flag==15)
{
}
else
{ Coordinates();
getGPS(); // Update the GPS location
getCompass(); // Update the CompaSerial Heading
//Ping(); // Use at your own discretion, this is not fully tested
}
}
void Coordinates()
{ Serial.println("i am here1");
// Send web page with input fields to client
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html);
});
// Send a GET request to <ESP_IP>/get?input1=<inputMessage>
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
String latitude1;
String latitude1Param;
String longitude1;
String longitude1Param;
String latitude2;
String latitude2Param;
String longitude2;
String longitude2Param;
String commitType;;
if (request->hasParam(PARAM_INPUT_2)||request->hasParam(PARAM_INPUT_1) ) {
// GET input1 value on <ESP_IP>/get?input1=<latitude>
latitude1 = request->getParam(PARAM_INPUT_1)->value();
latitude1Param = PARAM_INPUT_1;
// GET input2 value on <ESP_IP>/get?input2=<longitude>
longitude1 = request->getParam(PARAM_INPUT_2)->value();
longitude1Param = PARAM_INPUT_2;
// GET input3 value on <ESP_IP>/get?input3=<latitude>
latitude2 = request->getParam(PARAM_INPUT_3)->value();
latitude2Param = PARAM_INPUT_3;
// GET input4 value on <ESP_IP>/get?input4=<longitude>
longitude2 = request->getParam(PARAM_INPUT_4)->value();
longitude2Param = PARAM_INPUT_4;
}
else {
latitude1 = "No message sent";
latitude1Param = "none";
longitude1 = "No message sent";
longitude1Param = "none";
latitude2 = "No message sent";
latitude2Param = "none";
longitude2 = "No message sent";
longitude2Param = "none";
}
Serial.println(latitude1);
Serial.println(longitude1);
Serial.println(latitude2);
Serial.println(longitude2);
lati1=(latitude1.toFloat());
logi1=(longitude1.toFloat());
lati2=(latitude2.toFloat());
logi2=(longitude2.toFloat());
//Serial.println(lati,6);
//Serial.println(logi,6);
request->send(200, "text/html", "Command succesfuly sent""<br>Return to Home Page");
});
server.on("/go", HTTP_GET, [] (AsyncWebServerRequest *request) {
//logic for go here
Serial.println("YOYYYYO");
goWaypoint();
request->redirect("/");
});
server.on("/clear", HTTP_GET, [] (AsyncWebServerRequest *request) {
//logic for clear here
Serial.println("fdfghgh");
clearWaypoints();
request->redirect("/");
});
server.onNotFound(notFound);
server.begin();
}
void getGPS() // Get Latest GPS coordinates
{ Serial.println("i am here2");
while (S2.available() > 0)
gps.encode(S2.read());
}
// *************************************************************************************************************************************************
void setWaypoint() // Set up to 5 GPS waypoints
{
//if ((wpCount >= 0) && (wpCount < 50))
if (wpCount >= 0)
{
Serial.print("GPS Waypoint ");
Serial.print(wpCount + 1);
Serial.print(" Set ");
Home_LATarray[ac] = lati1 ; // store waypoint in an array
Home_LONarray[ac] = logi1 ; // store waypoint in an array
Home_LATarray[ac] = lati2 ; // store waypoint in an array
Home_LONarray[ac] = logi2 ; // store waypoint in an array
Serial.print("Waypoint #1: ");
Serial.print(Home_LATarray[0],6);
Serial.print(" , ");
Serial.println(Home_LONarray[0],6);
Serial.print("Waypoint #2: ");
Serial.print(Home_LATarray[1],6);
Serial.print(" , ");
Serial.println(Home_LONarray[1],6);
wpCount++; // increment waypoint counter
ac++; // increment array counter
}
else {Serial.print("Waypoints Full");}
}
// *************************************************************************************************************************************************
void clearWaypoints()
{
memset(Home_LATarray, 0, sizeof(Home_LATarray)); // clear the array
memset(Home_LONarray, 0, sizeof(Home_LONarray)); // clear the array
wpCount = 0; // reset increment counter to 0
ac = 0;
Serial.print("GPS Waypoints Cleared"); // display waypoints cleared
}
// *************************************************************************************************************************************************
void getCompass() // get latest compass value
{
Vector norm = compass.readNormalize();
// Calculate heading
float heading = atan2(norm.YAxis, norm.XAxis);
if(heading < 0)
heading += 2 * M_PI;
compass_heading = (int)(heading * 180/M_PI); // aSerialign compass calculation to variable (compass_heading) and convert to integer to remove decimal places
}
void Startup()
{
Serial.println("Pause for Startup... ");
for (int i=10; i >= 1; i--) // Count down for X seconds
{
Serial.print("Pause for Startup... ");
Serial.println(i);
delay(1000); // Delay for X seconds
}
Serial.println("Searching for Satellites ");
Serial.println("Searching for Satellites ");
while (Number_of_SATS <= 4) // Wait until x number of satellites are acquired before starting main loop
{
getGPS(); // Update gps data
Number_of_SATS = (int)(gps.satellites.value()); // Query Tiny GPS for the number of Satellites Acquired
}
setWaypoint(); // set intial waypoint to current location
wpCount = 0; // zero waypoint counter
ac = 0; // zero array counter
Serial.print(Number_of_SATS);
Serial.print(" Satellites Acquired");
}
void goWaypoint()
{
Serial.println("Go to Waypoint");
//Serial.print("Home_Latarray ");
//Serial.print(Home_LATarray[ac],6);
//Serial.print(" ");
//Serial.println(Home_LONarray[ac],6);
//Serial1.print("Distance to Home");
//Serial1.print(Distance_To_Home);
//Serial1.print("ac= ");
//Serial1.print(ac);
while (true)
{ // Start of Go_Home procedure
// bluetooth(); // Run the Bluetooth procedure to see if there is any data being sent via BT
if (blueToothVal == 5){break;} // If a 'Stop' Bluetooth command is received then break from the Loop
getCompass(); // Update Compass heading
getGPS(); // Tiny GPS function that retrieves GPS data - update GPS location// delay time changed from 100 to 10
if (millis() > 5000 && gps.charsProcessed() < 10) // If no Data from GPS within 5 seconds then send error
Serial.println(F("No GPS data: check wiring"));
Distance_To_Home = TinyGPSPlus::distanceBetween(gps.location.lat(),gps.location.lng(),Home_LATarray[ac], Home_LONarray[ac]); //Query Tiny GPS for Distance to Destination
GPS_Course = TinyGPSPlus::courseTo(gps.location.lat(),gps.location.lng(),Home_LATarray[ac],Home_LONarray[ac]); //Query Tiny GPS for Course to Destination
/*
if (Home_LATarray[ac] == 0) {
Serial1.print("End of Waypoints");
StopCar();
break;
}
*/
if (Distance_To_Home == 0) // If the Vehicle has reached it's Destination, then Stop
{
StopCar(); // Stop the robot after each waypoint is reached
Serial.println("You have arrived!"); // Print to Bluetooth device - "You have arrived"
ac++; // increment counter for next waypoint
break; // Break from Go_Home procedure and send control back to the Void Loop
// go to next waypoint
}
if ( abs(GPS_Course - compass_heading) <= 15) // If GPS Course and the Compass Heading are within x degrees of each other then go Forward
// otherwise find the shortest turn radius and turn left or right
{
Forward(); // Go Forward
} else
{
int x = (GPS_Course - 360); // x = the GPS desired heading - 360
int y = (compass_heading - (x)); // y = the Compass heading - x
int z = (y - 360); // z = y - 360
if ((z <= 180) && (z >= 0)) // if z is less than 180 and not a negative value then turn left otherwise turn right
{ SlowLeftTurn(); }
else { SlowRightTurn(); }
}
} // End of While Loop
}
wdt is the watchdog timer. It's a timer that is used to detect whether your code has crashed. If it's not reset periodically it will throw an error and restart the ESP32. The timer needs to be reset frequently.
Notice that the error says that it was the async_tcp task which was running when the watchdog timer trigger. You're using the AsyncWeb server, which uses async_tcp.
When the async web server gets a page request, it calls your code. You have handlers for individual pages. Those handlers need to treat the calls to them the way we have to deal with loop() - if you spend 3 seconds or more without returning or calling delay() or yield(). This gives the underlying software the chance to reset the watchdog timer.
Review your web page handlers. Look for where you may spend a long time in them.
You'll find that you call goWayPoint() in your handler for '/go'. It has a loop in it that may block for 5 seconds. 5 seconds is too long - if that loop doesn't return or call delay() the watchdog timer will fire, which it does.
The easy fix is to add a call to delay() in the while(true) loop.
while (true)
{
delay(1);
this will let the underlying code reset the watchdog timer.
That won't help if other parts of your code (getCompass(), getGPS() or other things) take too long.
Ultimately you should refactor your code. You're doing too much work in the web server callbacks. That work should be done in independent tasks - perhaps in loop(). But that's a big project. Adding a call to delay(1) anywhere in a web server callback that you have a while loop or make take some time to do some processing is clumsy but should solve this problem.
Welcome to the String heap fracturing club:
String latitude1;
String latitude1Param;
String longitude1;
String longitude1Param;
String latitude2;
String latitude2Param;
String longitude2;
String longitude2Param;
String commitType;;
in combination with async webserver is a huge problem. I rewrote a ~15.000 lines application to get rid of strings (also in the used libraries) and since then no resets and reboots anymore. Hope this helps you in your project.
Use predifined fixed char arrays they will go to the stack and keep heap corruption low.Use functions like strcpy, strcat, itoa / atoi to build messages or retrieve values.
EDIT: replace String class with fixed char arrays example
char numBuffer [16] ={'\0'} // For 15 chars and the null terminator
char latitude1 [32] ={'\0'} // For 31 chars and the null terminator
.... some code here ....
strcpy (latitude1 , "No values here");
//or
strcpy (latitude1 , "Value 1: ");
itoa (SomeIntDataNumber, numBuffer,10);
strcat (latitude1, numBuffer) // append the converted SomeIntDataNumber
One more thing if you use memset, make sure you do proper memory management, also check the used libraries for heavy use of String class. Some libs work in a static environment quite well, using them in a web context crashes the ESP. I had to ditch some libs or at least rewrite them without String class.
Further reading: https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/
Final Tip: Try to commenting out / replacing with dummy chars all appearancies of the String class and try the code again.
ESP-IDF creats a watchdog timer for idle tasks in addition to any tasks doing your work. IE, it creates two extra tasks IDLE0 & IDLE 1 (one for each core), whose sole purpose is to do nothing, ie idle. These idle tasks simply feed the watchdog whenever its respective core is idling. Whenever any task, in Arduino or in ESP-IDF, as well as interrupt routines, run with a higher priority than the IDLE tasks without delaying or blocking sufficiently long/often enough (such as when executing in a tight while loop), it triggers the watchdog, because that core is now fully busy, meaning it is no longer idling often enough, meaning the idle "tasks" get starved, so they can't reset the watchdog. Your app_main() in ESP-IDF and loop() in Arduino, run with higher priorities than the IDLE tasks. This is the source of the problem.
You either have to make some call that blocks your code for atleast 10mS in sufficient intervals, or you have to call yield() or
vTaskDelay(NUMBER_OF_MILLISECONDS_TO_DELAY / portTICK_PERIOD_MS)
with a minimum of 10mS (otherwise, due to discreteness, it amounts to 0, ie no delay at all, thus won't work. You can work around this by increasing the scheduler frequency).
An alternative is fully disabling the watchdog, but this nullifies its uses.
There is a more elegant solution. If you do need something to consume all available CPU time, and don't want to bother with considerations of delay or blocking, and don't want to disable the watchdog, but don't want it to bark, then put all intensive code operations in its own function or set of functions, and call it/each using the following task creation function:
xTaskCreate(someFunction, "HumanReadableNameofTask", 4096, NULL, tskIDLE_PRIORITY, NULL);
where your function has the following signature:
void someFunction(void* arg)
This won't trip the watchdog no matter what, because it uses the tskIDLE_PRIORITY priority. I'm not sure what value it has, but it seems greater than 10, because I tried 10 and it didn't work. Not sure if 11 did, which would be lower priority than the IDLE tasks. Note though, any code you place in someFunction(), won't execute at all except during times when the CPU is IDLE. So all your other code must still sleep/delay/block sufficiently enough to give it time to run. This is the ideal place for endless intensive code, such as motor control and PID control loops.
You can even do this in Arduino.

Why are my Verilog output registers only outputting "x"?

I've written the following module to take in a 12-bit stream of input, and run it through the Exponential Moving Average (EMA) formula. When simulating the program, it appears as if my output is a 12-bit stream of "don't cares". Regardless of what my input is, it isn't realized by the output register.
I'm a beginner at Verilog, so I'm sure there are a slew of issues here, but I expected to at least get some kind of output. Why is this behavior occurring and how can I fix it from occurring in the future? I've linked a screenshot of my waveform results at the bottom of this post.
My verilog module:
`timescale 1ns / 1ps
module EMATesting ( input signed [11:0] signal_in,
output reg signed [11:0] signal_out,
input clock_in,
input reset,
input enable,
output reg [11:0] newEMA);
reg [11:0] prevEMA;
reg [11:0] y;
reg [11:0] temp;
integer count = 0;
integer t = 1;
integer one = 1;
integer alpha = 0.5;
always #(posedge clock_in) begin
if (reset) begin
count = 0;
end
else if (count < 64) begin
count = count + 1;
end
//set the output equal to the first value received
if (count == 1) begin
newEMA = signal_in;
end
//if not the first value, run through the formula
else begin
temp = newEMA;
prevEMA = temp;
newEMA = alpha * signal_in + (one-alpha) * prevEMA;
count = count + 1;
end
end
endmodule
My verilog testbench:
`timescale 10ns / 1ns
module testbench_EMA;
reg signal_in;
reg clock_in, reset, enable;
wire [11:0] signal_out;
wire [11:0] newEMA;
initial begin
signal_in = 0; reset = 0; enable = 0;
clock_in = 0;
end
EMATesting DUT(signal_in, signal_out, clock_in, reset, enable, newEMA);
initial
begin
//test some values with timing intervals here
#100;
reset = 1;
#100;
reset = 0;
enable = 1;
#100;
//set signal_in to "1" repeating 12 times
signal_in = { 12 { 1'b1}};
#100;
reset = 1;
#100; //buffer to end simulation
$finish;
end
always
#5 clock_in = !clock_in;
endmodule
Waveform results of my testbench. Note that both output registers are giving no values.
There are many mistakes in your code. #Mr. Snrub listed some of them. You can correct the mistakes that are listed in the comments, and by further editing your code you can make it work as you wish, but there are more important fundamental problems. You have to solve them before you make further and hard to debug mistakes in the future, it also gives advantage of understanding HDL concepts better.
First of all, you need to understand the difference between software programming languages and hardware description languages. You should make further research for that, the mistakes you made are commonly made by developers who assume HDL is similar to software programming languages. Check this link for further information.
You need to further understand how the Verilog HDL (or any other HDL) codes are synthesized and why they are used.
Need to be familiar when and how to use blocking = or non-blocking <= assignments and how they work. Check this link.
When you research about the listed topics, you will understand that in edge sensitive (synchronous or sequential) always block, it is bad idea to use blocking = assignment.
When you use blocking assignment, the assignments are done in series, as in common software programming languages. In the case of edge sensitive always block, you have very limited time to finish all required assignments inside the always block.
In your case, as all the assignments inside the edge sensitive always block are blocking (assuming no reset condition):
First, it checks if count is less than 64, and completes the assignment if that is the case. All other assignments are waiting for that assignment to finish.
By the time the first assignment is done, the always block with posedge clock_in sensitivity might have ended execution and waiting for the next edge of the clock. So, other assignments are not done.
As you have not initialized your output registers, they initially were filled with 'don't cares' and new value is never assigned again, so, as a result, you got that output (filled with 'don't cares').
Even when count becomes larger than or equal to 64, you have other blocking assignments before you assign value to newEMA.

Matlab Newbie Binary Search Troubleshoot

I am a newbie to Matlab/programming in general. I wish to write a program/script that uses recursive binary search to approximate the root of $2x - 3sin(x)+5=0$, such that the iteration terminates once the truncation error is definitely $< 0.5 \times 10 ^{-5}$ and print out the number of iterations as well as the estimate of the root.
Here is my attempt that seems to have broken my computer...
%Approximating the root of f(x) = 2*x - 3*sin(x) + 5 by binary search
%Define variables
low = input('Enter lower bound of range: ');
high = input('Enter upper bound of range: ');
mid = (low + high)/2;
%Define f_low & f_high
f_low = 2*low - 3*sin(low) + 5;
f_high = 2*high - 3*sin(high) + 5;
f_mid = 2*mid - 3*sin(mid) + 5;
%Check that the entered range contains the key
while (f_low * f_high) > 0 || low > high
disp('Invalid range')
low = input('Enter lower bound of range: ');
high = input('Enter upper bound of range: ');
end
%The new range
while abs(f_mid) > 0.5*10^(-5)
if f_mid < 0
low = mid;
elseif f_mid > 0
high = mid;
end
end
fprintf('mid = %.4f \n', mid)
I haven't even added in the number-of-iterations counting bit (which I am not quite sure how to do) and already I am stuck.
Thanks for any help.
Once you set high=mid or low=mid, is mid and f_mid recalculated? It looks like you will fail if f_low>0 and f_high<0. This is a valid condition, but you are choosing the wrong one to reset in this case. Also, your termination check is on the function value, not the difference between low and high. This may be what you want, or maybe you want to check both ways. For very flat functions you may not be able to get the function value that small.
You don't need f_mid, and is in fact misleading you. You just need to calculate the value at each step, and see which direction to go.
Plus, you are just changing low and high, but you do not evaluate again f_low or f_high. Matlab is not an algebra system (there are modules for symbolic computation, but that's a different story), so you did not define f_low and f_high to change with the change of low and high: you have to reevaluate them in your final loop.

Cummulative array summation using OpenCL

I'm calculating the Euclidean distance between n-dimensional points using OpenCL. I get two lists of n-dimensional points and I should return an array that contains just the distances from every point in the first table to every point in the second table.
My approach is to do the regular doble loop (for every point in Table1{ for every point in Table2{...} } and then do the calculation for every pair of points in paralell.
The euclidean distance is then split in 3 parts:
1. take the difference between each dimension in the points
2. square that difference (still for every dimension)
3. sum all the values obtained in 2.
4. Take the square root of the value obtained in 3. (this step has been omitted in this example.)
Everything works like a charm until I try to accumulate the sum of all differences (namely, executing step 3. of the procedure described above, line 49 of the code below).
As test data I'm using DescriptorLists with 2 points each:
DescriptorList1: 001,002,003,...,127,128; (p1)
129,130,131,...,255,256; (p2)
DescriptorList2: 000,001,002,...,126,127; (p1)
128,129,130,...,254,255; (p2)
So the resulting vector should have the values: 128, 2064512, 2130048, 128
Right now I'm getting random numbers that vary with every run.
I appreciate any help or leads on what I'm doing wrong. Hopefully everything is clear about the scenario I'm working in.
#define BLOCK_SIZE 128
typedef struct
{
//How large each point is
int length;
//How many points in every list
int num_elements;
//Pointer to the elements of the descriptor (stored as a raw array)
__global float *elements;
} DescriptorList;
__kernel void CompareDescriptors_deb(__global float *C, DescriptorList A, DescriptorList B, int elements, __local float As[BLOCK_SIZE])
{
int gpidA = get_global_id(0);
int featA = get_local_id(0);
//temporary array to store the difference between each dimension of 2 points
float dif_acum[BLOCK_SIZE];
//counter to track the iterations of the inner loop
int loop = 0;
//loop over all descriptors in A
for (int i = 0; i < A.num_elements/BLOCK_SIZE; i++){
//take the i-th descriptor. Returns a DescriptorList with just the i-th
//descriptor in DescriptorList A
DescriptorList tmpA = GetDescriptor(A, i);
//copy the current descriptor to local memory.
//returns one element of the only descriptor in DescriptorList tmpA
//and index featA
As[featA] = GetElement(tmpA, 0, featA);
//wait for all the threads to finish copying before continuing
barrier(CLK_LOCAL_MEM_FENCE);
//loop over all the descriptors in B
for (int k = 0; k < B.num_elements/BLOCK_SIZE; k++){
//take the difference of both current points
dif_acum[featA] = As[featA]-B.elements[k*BLOCK_SIZE + featA];
//wait again
barrier(CLK_LOCAL_MEM_FENCE);
//square value of the difference in dif_acum and store in C
//which is where the results should be stored at the end.
C[loop] = 0;
C[loop] += dif_acum[featA]*dif_acum[featA];
loop += 1;
barrier(CLK_LOCAL_MEM_FENCE);
}
}
}
Your problem lies in these lines of code:
C[loop] = 0;
C[loop] += dif_acum[featA]*dif_acum[featA];
All threads in your workgroup (well, actually all your threads, but lets come to to that later) are trying to modify this array position concurrently without any synchronization whatsoever. Several factors make this really problematic:
The workgroup is not guaranteed to work completely in parallel, meaning that for some threads C[loop] = 0 can be called after other threads have already executed the next line
Those that execute in parallel all read the same value from C[loop], modify it with their increment and try to write back to the same address. I'm not completely sure what the result of that writeback is (I think one of the threads succeeds in writing back, while the others fail, but I'm not completely sure), but its wrong either way.
Now lets fix this:
While we might be able to get this to work on global memory using atomics, it won't be fast, so lets accumulate in local memory:
local float* accum;
...
accum[featA] = dif_acum[featA]*dif_acum[featA];
barrier(CLK_LOCAL_MEM_FENCE);
for(unsigned int i = 1; i < BLOCKSIZE; i *= 2)
{
if ((featA % (2*i)) == 0)
accum[featA] += accum[featA + i];
barrier(CLK_LOCAL_MEM_FENCE);
}
if(featA == 0)
C[loop] = accum[0];
Of course you can reuse other local buffers for this, but I think the point is clear (btw: Are you sure that dif_acum will be created in local memory, because I think I read somewhere that this wouldn't be put in local memory, which would make preloading A into local memory kind of pointless).
Some other points about this code:
Your code is seems to be geared to using only on workgroup (you aren't using either groupid nor global id to see which items to work on), for optimal performance you might want to use more then that.
Might be personal preferance, but I to me it seems better to use get_local_size(0) for the workgroupsize than to use a Define (since you might change it in the host code without realizing you should have changed your opencl code to)
The barriers in your code are all unnecessary, since no thread accesses an element in local memory which is written by another thread. Therefore you don't need to use local memory for this.
Considering the last bullet you could simply do:
float As = GetElement(tmpA, 0, featA);
...
float dif_acum = As-B.elements[k*BLOCK_SIZE + featA];
This would make the code (not considering the first two bullets):
__kernel void CompareDescriptors_deb(__global float *C, DescriptorList A, DescriptorList B, int elements, __local float accum[BLOCK_SIZE])
{
int gpidA = get_global_id(0);
int featA = get_local_id(0);
int loop = 0;
for (int i = 0; i < A.num_elements/BLOCK_SIZE; i++){
DescriptorList tmpA = GetDescriptor(A, i);
float As = GetElement(tmpA, 0, featA);
for (int k = 0; k < B.num_elements/BLOCK_SIZE; k++){
float dif_acum = As-B.elements[k*BLOCK_SIZE + featA];
accum[featA] = dif_acum[featA]*dif_acum[featA];
barrier(CLK_LOCAL_MEM_FENCE);
for(unsigned int i = 1; i < BLOCKSIZE; i *= 2)
{
if ((featA % (2*i)) == 0)
accum[featA] += accum[featA + i];
barrier(CLK_LOCAL_MEM_FENCE);
}
if(featA == 0)
C[loop] = accum[0];
barrier(CLK_LOCAL_MEM_FENCE);
loop += 1;
}
}
}
Thanks to Grizzly, I have now a working kernel. Some things I needed to modify based in the answer of Grizzly:
I added an IF statement at the beginning of the routine to discard all threads that won't reference any valid position in the arrays I'm using.
if(featA > BLOCK_SIZE){return;}
When copying the first descriptor to local (shared) memory (i.g. to Bs), the index has to be specified since the function GetElement returns just one element per call (I skipped that on my question).
Bs[featA] = GetElement(tmpA, 0, featA);
Then, the SCAN loop needed a little tweaking because the buffer is being overwritten after each iteration and one cannot control which thread access the data first. That is why I'm 'recycling' the dif_acum buffer to store partial results and that way, prevent inconsistencies throughout that loop.
dif_acum[featA] = accum[featA];
There are also some boundary control in the SCAN loop to reliably determine the terms to be added together.
if (featA >= j && next_addend >= 0 && next_addend < BLOCK_SIZE){
Last, I thought it made sense to include the loop variable increment within the last IF statement so that only one thread modifies it.
if(featA == 0){
C[loop] = accum[BLOCK_SIZE-1];
loop += 1;
}
That's it. I still wonder how can I make use of group_size to eliminate that BLOCK_SIZE definition and if there are better policies I can adopt regarding thread usage.
So the code looks finally like this:
__kernel void CompareDescriptors(__global float *C, DescriptorList A, DescriptorList B, int elements, __local float accum[BLOCK_SIZE], __local float Bs[BLOCK_SIZE])
{
int gpidA = get_global_id(0);
int featA = get_local_id(0);
//global counter to store final differences
int loop = 0;
//auxiliary buffer to store temporary data
local float dif_acum[BLOCK_SIZE];
//discard the threads that are not going to be used.
if(featA > BLOCK_SIZE){
return;
}
//loop over all descriptors in A
for (int i = 0; i < A.num_elements/BLOCK_SIZE; i++){
//take the gpidA-th descriptor
DescriptorList tmpA = GetDescriptor(A, i);
//copy the current descriptor to local memory
Bs[featA] = GetElement(tmpA, 0, featA);
//loop over all the descriptors in B
for (int k = 0; k < B.num_elements/BLOCK_SIZE; k++){
//take the difference of both current descriptors
dif_acum[featA] = Bs[featA]-B.elements[k*BLOCK_SIZE + featA];
//square the values in dif_acum
accum[featA] = dif_acum[featA]*dif_acum[featA];
barrier(CLK_LOCAL_MEM_FENCE);
//copy the values of accum to keep consistency once the scan procedure starts. Mostly important for the first element. Two buffers are necesarry because the scan procedure would override values that are then further read if one buffer is being used instead.
dif_acum[featA] = accum[featA];
//Compute the accumulated sum (a.k.a. scan)
for(int j = 1; j < BLOCK_SIZE; j *= 2){
int next_addend = featA-(j/2);
if (featA >= j && next_addend >= 0 && next_addend < BLOCK_SIZE){
dif_acum[featA] = accum[featA] + accum[next_addend];
}
barrier(CLK_LOCAL_MEM_FENCE);
//copy As to accum
accum[featA] = GetElementArray(dif_acum, BLOCK_SIZE, featA);
barrier(CLK_LOCAL_MEM_FENCE);
}
//tell one of the threads to write the result of the scan in the array containing the results.
if(featA == 0){
C[loop] = accum[BLOCK_SIZE-1];
loop += 1;
}
barrier(CLK_LOCAL_MEM_FENCE);
}
}
}