|
Haha that is the longest winded writing of these dozen lines of code for the Pi3 .. gpio is the volatile address you use
static volatile uint32_t *gpio;
int fd ;
if ((fd = open ("/dev/mem", O_RDWR | O_SYNC) ) < 0) {
if ((fd = open ("/dev/gpiomem", O_RDWR | O_SYNC) ) < 0){
printf("Unable to open physical memory handle: %s\n", strerror(errno));
return -1;
}
}
gpio = (uint32_t *)mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x3F200000);
if ((int32_t)gpio < 0){
printf("Mmap failed: %s\n", strerror(errno));
return -1;
}
So looking at the code GPIOmem is an entry value >>>> you provide to the function <<<<.
If you provide 0 it basically means Autodetect the base address
If you provide any number it will use that number as the base address ignoring all the autodetection routines.
Okay this pile of rubbish is just reading the device table file (hence the DT). Its just returning a number from a file it's not volatile and this junk should be a function so I would make it one. It will return 0 if it can't find the entry in the DT file and the address if it find it.
I am going to dump all the long winded debug code, it's just making a mess of what is actually happening so here is your function
uint32_t BaseAddressFromDTFile (void)
{
uint32_t base_addr = 0;
FILE *fp;
if ((fp = fopen(BMC2835_RPI2_DT_FILENAME, "rb"))) {
uint32_t base_size;
unsigned char buf[4];
fseek(fp, BMC2835_RPI2_DT_PERI_BASE_ADDRESS_OFFSET, SEEK_SET);
if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf))
base_addr = (uint32_t *) (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0);
fseek(fp, BMC2835_RPI2_DT_PERI_SIZE_OFFSET, SEEK_SET);
if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf))
base_size = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0);
fclose(fp);
}
return (base_addr);
}
If that returns 0 it looks like it assumes it's a Pi1
Next it just tries to Obtain handle to physical memory which the reduce form is above in my code
Then if you set GPIOMem to zero it will use that address found otherwise it use the GPIOMem address to map the page.
Then it does the page map with
bcm2835_peripherals = (uint32_t*) mapmem("gpio", bcm2835_peripherals_size,
memfd, (uint32_t) bcm2835_peripherals_base);
We don't have the definition of bcm2835_peripherals but that is the thing that should be volatile like my code above it is their version of gpio.
In vino veritas
modified 20-May-18 10:48am.
|
|
|
|
|
I am really sorry for the messy post.
Being an OF I need to keep track of myself and such code is very difficult to post in public. But if I do not - then I get asked "what is this for etc".
O well.
I am rewriting the whole mess and getting rid of some fluff.
There is one thing I am not sure about
The memory can be mapped using /dev/mem which gives "access to all" but has to have user root.
I am not sure but my "remote TCF" is probably root.
I need to recheck that - this TCF is not too bright to report some problems.
Using /dev/gpiomem lets Linux take care of access permissions , BUT is it then limited ONLY to GPIO ?
I need access to ALT0 - SPI.
Thanks for putting up with my foolishnes.
Cheers
Vaclav
|
|
|
|
|
Each device has it's own name it's basically the name in the process device (look at the /dev directory you can see them all)
Now the SPI is a proper block device and you can write to it like a file unlike the GPIO
so for SPI it's either
/dev/spidev0.0
/dev/spidev0.1
Depending if you want SPI0 or 1
Lets do SPI0
#include <stdbool.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <unistd.h>
int OpenSPI( int SPI_Port, int* SPI_WriteMode, int* SPI_ReadMode, int* SPI_WriteLength, int* SPI_ReadLength, int* SPI_WriteSpeed, int* SPI_ReadSpeed)
{
int status;
int spi_handle = -1;
if (SPI_Port) == 0){
spi_handle = open ("/dev/spidev0.0", O_RDWR);
} else if (SPI_Port == 1) {
spi_handle = open ("/dev/spidev0.1", O_RDWR)
} else {
printf("Invalid SPI port number specified\n");
return -1;
}
if (spi_handle < 0) {
printf("Unable to open physical memory handle: %s\n", strerror(errno));
return -1;
}
status = ioctl(spi_handle, SPI_IOC_WR_MODE, SPI_WriteMode);
if(status < 0) {
printf("Could not set SPIMode (WR)...ioctl fail");
return -1;
}
status = ioctl(spi_handle, SPI_IOC_RD_MODE, SPI_ReadMode);
if(status < 0) {
printf("Could not set SPIMode (RD)...ioctl fail");
return(-1);
}
status = ioctl(spi_handle, SPI_IOC_WR_BITS_PER_WORD, SPI_WriteLength);
if (status < 0) {
printf("Could not set SPI bitsPerWord (WR)...ioctl fail");
return -1;
}
status = ioctl(spi_handle, SPI_IOC_RD_BITS_PER_WORD, SPI_ReadLength);
if (status < 0) {
printf("Could not set SPI bitsPerWord(RD)...ioctl fail");
return -1;
}
status = ioctl(spi_handle, SPI_IOC_WR_MAX_SPEED_HZ, SPI_WriteSpeed);
if (status < 0) {
printf("Could not set SPI speed (WR)...ioctl fail");
return -1;
}
status = ioctl(spi_handle, SPI_IOC_RD_MAX_SPEED_HZ, SPI_ReadSpeed);
if (status < 0) {
printf("Could not set SPI speed (RD)...ioctl fail");
return -1;
}
return (spi_handle);
}
int SpiWrite (int spi_device, int SPI_WriteSpeed, int SPI_WriteLength, unsigned char *data, int length)
{
struct spi_ioc_transfer spi[length];
int i = 0;
int retVal = -1;
for (i = 0 ; i < length ; i++)
{
memset(&spi[i], 0, sizeof (spi[i]));
spi[i].tx_buf = (unsigned long)(data + i);
spi[i].rx_buf = 0;
spi[i].len = length;
spi[i].delay_usecs = 0 ;
spi[i].speed_hz = SPI_WriteSpeed;
spi[i].bits_per_word = SPI_WriteLength;
spi[i].cs_change = 0;
}
retVal = ioctl(spi_device, SPI_IOC_MESSAGE(length), &spi);
if (retVal < 0){
printf("Error - Problem transmitting spi data..ioctl");
return(-1);
}
return retVal;
}
int SpiRead (int spi_device, int SPI_ReadSpeed, int SPI_ReadLength, unsigned char *data, int length)
{
struct spi_ioc_transfer spi[length];
int i = 0;
int retVal = -1;
for (i = 0 ; i < length ; i++)
{
memset(&spi[i], 0, sizeof (spi[i]));
spi[i].tx_buf = 0;
spi[i].rx_buf = (unsigned long)(data + i) ;
spi[i].len = length;
spi[i].delay_usecs = 0 ;
spi[i].speed_hz = SPI_ReadSpeed;
spi[i].bits_per_word = SPI_ReadLength;
spi[i].cs_change = 0;
}
retVal = ioctl(spi_device, SPI_IOC_MESSAGE(length), &spi) ;
if(retVal < 0) {
printf("Error - Problem transmitting spi data..ioctl");
return -1;
}
return retVal;
}
Okay finally thats is all done lets use everything
int main (void){
static int WriteSpeed = 1000000;
static int ReadSpeed = 1000000;
static int WriteLength = 8;
static int ReadLength = 8;
static int WriteMode = SPI_MODE_0 ;
static int ReadMode = SPI_MODE_0;
static int SPI_handle;
SPI_handle = OpenSPI(0, &WriteMode, &ReadMode, &WriteLength, &ReadLength, &WriteSpeed, &ReadSpeed);
if (SPI_handle >= 0){
unsigned char Data[4] = { 0x41, 0x42, 0x43, 0x44};
SpiWrite(SPI_handle, WriteSpeed, WriteLength, &Data[0], 4);
close(SPI_handle);
}
}
Now the read/write routines are less than optimal I would bring the struct out to the interface but it will get you started.
In vino veritas
|
|
|
|
|
Thanks again, I am making much progress with your help.
I think I found the initial problem with using "volatile".
Here is my view in pseudo code - using GPIO as an example :
pointer * to GPIO block = pointer * to base memory block + offset to gpio
Now - what would be of benefit using volatile to POINTER such as
volatile pointer * to GPIO block = pointer * to base memory block + offset to gpio
In my interpretation - volatile keyword is to protect variable VALUE , not the pointer.
It compiles but the resulting pointer is always "1".
Leon,
I really need to resolve this "volatile" problem.
I actually tried few different ways to output data the LCD /TFT device.
Using /dev/spidev0.0 (ioctl) writing and reading , using /dev/spidev0.0 and ioctl "writing / reading messages ", plain GPIO access and now this "library".
The main issue is that the LCD/TFT is really not true SPI device - it requires switching from writing data to writing command. That is why I am trying to use this BCM library.
I figure if I can do the "low level BCM library stuff " I can adopt the ioctl way later.
-- modified 21-May-18 10:39am.
|
|
|
|
|
Sometimes you want to read a status continually in a loop lets show you a sample
#include <stdint.h>
#define STATUS_PORT 0x3F000000;
int main (void){
uint32_t* p = (uint32_t*) STATUS_PORT;
do {} while (*p != 1);
}
Now don't worry about the address the code will fail if you have an optimizer turned on ... it will produce this
main:
mov r3, #1056964608
ldr r3, [r3]
cmp r3, #1
beq .L2
.L3:
b .L3
.L2:
mov r0, #0
bx lr
Hopefully you see the problem with the branch L3 loop its a deadloop doing nothing ... so you may ask why does it do it.
Well the code read the port at line 2 with ldr r3, [r3]
As far as the optimizer is concerned the value never changes so it thinks you are just asking for a deadloop with the while loop.
The optimizer has no way to know the port value can change independent of the running code.
What the volatile does is tell the optimizer the value can change without it knowing so it must read it everytime so lets do this
#include <stdint.h>
#define STATUS_PORT 0x3F000000;
int main (void){
volatile uint32_t* p = (uint32_t*) STATUS_PORT;
do {} while (*p != 1);
}
Now what you get is this
main:
mov r2, #1056964608
.L2:
ldr r3, [r2]
cmp r3, #1
bne .L2
mov r0, #0
bx lr
See the difference in the L2 loop it reads the port everytime
So what the volatile is protecting you from is the optimizer making bad assumptions that the registers can't change.
That is all it's doing it makes sure that the optimizer knows the register value can change without the optimizer knowing.
Now it doesn't have to be a single register so long as you use the pointer anything at the pointer is volatile so consider this
#include <stdint.h>
#define STATUS_PORT 0x3F000000;
struct mystruct {
uint32_t port1;
uint32_t port2;
};
int main(void) {
struct mystruct* p = (struct mystruct*)STATUS_PORT;
do {} while (p->port1 != 1);
do {} while (p->port2 != 2);
}
Again it gets it wrong on both ports ... see L3 and L5 .. deadloops again doing nothing
main:
mov r3, #1056964608
ldr r2, [r3]
cmp r2, #1
beq .L2
.L3:
b .L3
.L2:
ldr r3, [r3, #4]
cmp r3, #2
beq .L4
.L5:
b .L5
.L4:
mov r0, #0
bx lr
Now put a volatile on the pointer
#include <stdint.h>
#define STATUS_PORT 0x3F000000;
struct mystruct {
uint32_t port1;
uint32_t port2;
};
int main(void) {
volatile struct mystruct* p = (struct mystruct*)STATUS_PORT;
do {} while (p->port1 != 1);
do {} while (p->port2 != 2);
}
The compiler knows the ports pointed to by the pointer can change and produces the right code
main:
mov r2, #1056964608
.L2:
ldr r3, [r2]
cmp r3, #1
bne .L2
mov r2, #1056964608
.L3:
ldr r3, [r2, #4]
cmp r3, #2
bne .L3
mov r0, #0
bx lr
So there is your answer what the volatile does, its basically a thing to stop optimizer errors.
You only need it on things that can change outsize the running code like HARDWARE REGISTERS or data accessed by 2 processes of multitask code.
In vino veritas
modified 21-May-18 13:50pm.
|
|
|
|
|
I am "porting" C code into C++, mainly to gain an experience.
Run into this , undocumented , piece of code.
Did some reading and have basic understanding WHAT is suppose to do.
Preventing multiprocessors to clobber each other or multiple access to shared devices / memory.
So far my software is for single CPU and no sharing of I/O , not yet.
That is NOT my concern.
What I would like to know why it stops running the process PAST the first usage of
__sync_synchronize();
It compiles just fine.
<pre lang="c++">
__sync_synchronize();
STOPS HERE
ret = *paddr;
__sync_synchronize();
</pre>
Thanks
Cheers Vaclav
|
|
|
|
|
Hi,
You obviously have a race condition somewhere in your code. As you have probably discovered... that intrinsic function is a memory barrier.
There's no way to fix this without learning how to debug your code. If you are developing on the Windows platform then fire up WinDbg and attach it to the process and type '!locks'
Debugging a Deadlock[^]
Best Wishes,
-David Delaune
|
|
|
|
|
David, thanks for reply.
Upon further invetsigation I believe "my problem" is elsewhere in code since it stops on the line between the calls to the __sync_synchronize.
Vaclav
|
|
|
|
|
Well,
Yes; deadlocks, race conditions by the very definition means "somewhere else" is holding a lock.
You are looking at the code not me. But I wouldn't recommend using the "Current Line" in the source-view as my error indicator. You need to be looking at the callstack and instructions. My recommendations remain: Attach a debugger to the process. If you want an automated analysis of the deadlock you can attach WinDbg and do: analyze -v -hang
Are you developing on Windows? My mind reading skills are not working today.
Best Wishes,
-David Delaune
|
|
|
|
|
David,
I have "discovered" the real problem - nothing to do with
synchronization. ( see my recent "volatile misbehaves " post. )
I am sorry for wasting your time on this, my apology.
|
|
|
|
|
Is it possible to install Visual Studio(2008 Pro,2010 Express and 2013 Express) in the same machine. Will there be any problem.
|
|
|
|
|
I guess it is possible.
Why didn't you try?
|
|
|
|
|
I tried it...but installed VS2008 at the last. But i was unable to open the VS2008 project which was originally created in VS2008.
|
|
|
|
|
|
We had a project created in VS2008. When we copied the project to this machine, the project files and all associated files had the icon appearance changed to VS2013. And when we tried to open the project solution file (Originally created in VS2008), the VS2013 opens up and didnt have any files associated with the project in the solution explorer.
|
|
|
|
|
Did you try to first open the VS2008 IDE, and open the project from this IDE?
|
|
|
|
|
Yes. I tried in Vs2008 only
|
|
|
|
|
You have always been able to install Visual Studio in side by side format with earlier versions.
However that said unless you targetting windows O/S prior to XP or had a mountain of difficult legacy code there would be little point.
The free version of Visual Studio 2017 is much easier and going to cause you less problems than libraries written for the old windows O/S.
In vino veritas
|
|
|
|
|
Strange...
A few years back I had in my XP virtual machine VC++6.0, VS2008 and VS2010 installed. And I could choose any of them to build the project.
And I never saw the problem similar to what you have described.
|
|
|
|
|
Yes, but;
1) I highly suggest you install them from oldest to newest.
2) Do NOT open a solution by double-clicking in explorer. Rather, open the visual studio you want to use and then open the solution from there. Also be aware that once you move a solution to a newer version, you typically cannot move back.
Also note that starting with either 2013 or 2015, you can use an earlier toolset.
|
|
|
|
|
Hi. I am trying to get the source code of a web page in order to analyze it. And here is the code for code retrieving:
BOOL CCIFDoc::GetRemoteFile(CString sServer, CString sRemotePath, CString sParameter, CStringArray& saData)
{
BOOL bRet = FALSE;
CInternetSession ISession;
CInternetFile* pIFile = NULL;
CHttpFile* pHttpFile = NULL;
LPCTSTR lpszAccept[] = {_T("*/*"), NULL};
try
{
pIFile = (CInternetFile*)ISession.OpenURL(_T("http://") + sServer + sRemotePath + sParameter, 1, INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_RELOAD);
if(NULL != pIFile)
{
CString sTemp;
while(pIFile->ReadString(sTemp))
saData.Add(sTemp + _T("\n"));
}
bRet = (saData.GetSize() > 0);
}
catch(CInternetException* pException)
{
pException->GetErrorMessage(m_sError.GetBuffer(_MAX_PATH), _MAX_PATH);
m_sError.ReleaseBuffer();
pException->Delete();
}
catch(CMemoryException* pMemException)
{
pMemException->GetErrorMessage(m_sError.GetBuffer(_MAX_PATH), _MAX_PATH);
m_sError.ReleaseBuffer();
pMemException->Delete();
}
if(NULL != pIFile)
{
pIFile->Close();
delete pIFile;
}
if(NULL != pHttpConnect)
{
pHttpConnect->Close();
delete pHttpConnect;
}
ISession.Close();
return bRet;
}
Classic code.
But there is some web pages which is retrieving without html body, or with other body than I have seen in my browser. Let's take an example: type www.bnr.ro in your browser, and see the page. But when I retrieve this address with code from above, here is the result:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Eroare/ Error</title>
<style type="text/css">
* { margin: 0; padding: 0; border: 0; outline: none; font-size: 100%; }
body { font-family: Arial, sans-serif; }
#wrapper { text-align: center; margin: 3em auto;}
p { padding: 0.5em 0; }
a { color: #0039a6; text-decoration: none; }
a:hover, a:focus { color: #e9994a; }
</style>
</head>
<body>
<div id="wrapper">
<a href="http://www.bnr.ro"><img src="http://www.bnr.ro/images/logo.png"></a>
<p>Eroare neprevazută / Unexpected error.</p>
<p><a href="http://www.bnr.ro">Înapoi pe prima pagină / Back to the homepage</a>.</p>
</div>
</body>
</html>
How can I retrieve the source code just I seen in my browser ?
Thank you.
modified 14-May-18 7:34am.
|
|
|
|
|
That is an error message. The server was not able to answer the request.
If you enter that address in your browser you should have noticed that it redirects to an ASPX page.
A possible reason might be that the server script tries to access a request header which is not present and the code does not handle that. Candidates are (among others) User-Agent , Content-Type , and Accept . But finally only the administrator of that web site can tell you.
|
|
|
|
|
Ok, and if I know them (User-Agent, Content-Type, etc.), how can I use it in OpenURL method ?
|
|
|
|
|
Fourth parameter of OpenURL() .
|
|
|
|
|
|